-
Notifications
You must be signed in to change notification settings - Fork 98
supported link to model in serialize/deserialize #5240
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
supported link to model in serialize/deserialize #5240
Conversation
f1e04d2 to
29e9bc8
Compare
source/MRMesh/MRObjectMeshHolder.cpp
Outdated
| if ( const auto objectMeshHolder = dynamic_cast< const ObjectMeshHolder* >( &other ) ) | ||
| { | ||
| // can we compare vert colors ? | ||
| return data_.mesh == objectMeshHolder->data_.mesh && data_.vertColors == objectMeshHolder->data_.vertColors; |
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.
Not all mesh formats include vertex colors, need to check MeshSaverCapabilities first, I think.
source/MRMesh/MRObjectSave.cpp
Outdated
| std::error_code ec; | ||
| if ( !std::filesystem::is_directory( sharedFolder, ec ) ) | ||
| if ( !std::filesystem::create_directories( sharedFolder, ec ) ) | ||
| return MR::unexpected( "Cannot create directories " + MR::utf8string( sharedFolder ) ); |
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.
Do we need MR:: here?
source/MRMesh/MRObjectSave.cpp
Outdated
| if ( node->isAncillary() ) | ||
| continue; // consider ancillary_ objects as temporary, not requiring saving | ||
|
|
||
| auto it = links.find( { node } ); |
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.
you can use insert instead of find + [], insert returns indication whether new item was added or already was in map
source/MRMesh/MRObject.h
Outdated
|
|
||
| /// Reads model from file | ||
| MRMESH_API virtual Expected<void> deserializeModel_( const std::filesystem::path& path, ProgressCallback progressCb = {} ); | ||
| /// reads model from oter object |
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.
oter -> other, reads - > shares
source/MRMesh/MRObject.h
Outdated
| [[nodiscard]] MRMESH_API virtual size_t heapBytes() const; | ||
|
|
||
| // return true if model of current object equals to model of other | ||
| MRMESH_API virtual bool isModelEqual( const Object& other ) const; |
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.
better name something like sameModels or areModelsEqual
source/MRMesh/MRObject.h
Outdated
|
|
||
| /// \} | ||
|
|
||
| struct KeyObjectModel |
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.
why do we need it?
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.
Because we need key for comapring objectA and objectB and in this logic of shared models we consider them equal when equal (the same) them models
source/MRMesh/MRObject.h
Outdated
|
|
||
| struct LinkData | ||
| { | ||
| std::string link; // relative path (link) to shared model file |
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.
if it is a path, then better use std::filesystem::path
source/MRMesh/MRObject.h
Outdated
| // map for mapping Objects to relative path (link) to shared model (used while serialization) | ||
| using MapSharedObjectModelToLinkData = std::unordered_map<KeyObjectModel, LinkData, KeyObjectModelHasher>; | ||
| // map for mapping relative path (link) to shared model file to first deserialized Object (used while deserialization) | ||
| using MapLinkToSharedObjectModel = std::unordered_map<std::string, const Object*>; |
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.
why do we need both?
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.
I don't understund
- first map for serialization
we need key for comparing ObjectA and ObjectB and in this logic of shared models we consider them equal when equal (the same) them models. After collecting all links to shared objects we have map
with pairs <ObjectA, SharedModels/N_model> and while serializing we map objectA to SharedModels/N_model and save model file and save SharedModels/N_model to root["Link"], ObjectB equals (have the same model as ObjectA ), and we no need to serialize his model we just save link to already saved model file to root["Link"]
2.second map for deserialization
This map empty before deserialization
after deserialize model of object ObjectA, we save to map values <SharedModels/N_model, ObjectA> and while deserializing ObjectB we get the same link to file via root["Link"], and find in map that SharedModels/N_model have already deserialized by ObjectA and we get model from ObjectA an set it to ObjectB via ObjectB.setSharedModel_(ObjectA)
source/MRMesh/MRObject.h
Outdated
| MRMESH_API MR_BIND_IGNORE Expected<std::vector<std::future<Expected<void>>>> serializeRecursive( const std::filesystem::path& path, Json::Value& root, | ||
| int childId, const std::filesystem::path& rootFolder, MapSharedObjectModelToLinkData* mapSharedObjectModelToLinkData = nullptr ) const; |
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.
why do we need to pass rootFolder?
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.
we have relative path in Link struct we need known physical path for directory while serialization
PS we can save rootFolder to LinkData but i made the same as in deserializeRecursive()
source/MRMesh/MRObject.h
Outdated
| MRMESH_API Expected<void> deserializeRecursive( const std::filesystem::path& path, const Json::Value& root, const std::filesystem::path& rootFolder, | ||
| ProgressCallback progressCb = {}, int* objCounter = nullptr, MapLinkToSharedObjectModel* mapLinkToSharedObjectModel = nullptr ); |
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.
same
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.
we have relative path in Link field of json and we need known physical path for directory while deserialization
source/MRMesh/MRObject.cpp
Outdated
| } | ||
|
|
||
| Expected<std::vector<std::future<Expected<void>>>> Object::serializeRecursive( const std::filesystem::path& path, Json::Value& root, int childId ) const | ||
| Expected<std::vector<std::future<Expected<void>>>> Object::serializeRecursive( const std::filesystem::path& path, Json::Value& root, int childId, const std::filesystem::path& rootFolder, MapSharedObjectModelToLinkData* mapSharedObjectModelToLinkData ) const |
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.
what if we move this implementation into protected serializeRecursive_ function with input parameters structure and implement this one like this:
void serializeRecursive_(...)
{
// current implementation
serializeRecursive_();
}
void serialize( )
{
// build map with links
serializeRecursive_(); // will all extra parameters, so we don't need to change ObjectSave/ObjectLoad
}
source/MRMesh/MRObject.cpp
Outdated
| if ( !res.has_value() ) | ||
| return res; | ||
| std::string link; | ||
| if ( !root["Link"].empty() ) |
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.
better to check root["Link"].isString() too
source/MRMesh/MRObject.h
Outdated
| struct LinkData | ||
| { | ||
| std::string link; // relative path (link) to shared model file | ||
| bool serialized = false; // set true after first serialization to avoid other model copies | ||
| }; |
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.
can we use const Object* instead of this structure? (so it will be single MapType for both serialization and deserialization)
auto it = map.find( this );
if ( it != map.end() )
// add link from it->second->createLink()
else
// serialize as not-shared model
if ( it != map.end() && it->second == this )
// serialize as shared model
source/MRMesh/MRObject.h
Outdated
| /// reads model from oter object | ||
| MRMESH_API virtual Expected<void> setModelFromObject_( const Object& other ); |
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.
lets rename it to something like setSharedModel_, and add comment that it differs form simple setModel because some Object types consider different fields as model
source/MRMesh/MRObjectMeshHolder.cpp
Outdated
| Expected<void> ObjectMeshHolder::setModelFromObject_( const Object& other ) | ||
| { | ||
| if ( const auto objectMeshHolder = dynamic_cast< const ObjectMeshHolder* >( &other ) ) | ||
| { | ||
| data_.mesh = objectMeshHolder->data_.mesh; | ||
| data_.vertColors = objectMeshHolder->data_.vertColors; | ||
| return{}; | ||
| } | ||
| return unexpected("Invalid object type"); | ||
| } |
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.
can we use setData here?
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.
No, because we get some fields of data_ from json, may be in future all model data saved to file move to separate struct?
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.
Than we should validate format capabilities in this check, because if we cannot save vert map in model we will save it in json (for example for mrmesh format), and same logic will be applicable for it
source/MRMesh/MRObjectSave.cpp
Outdated
| // collect links to shared models | ||
| MapSharedObjectModelToLinkData links; | ||
| std::filesystem::path sharedFolder; | ||
| const auto countSharedFiles = collectLinks(object, scenePath, links, sharedFolder ); | ||
| if ( countSharedFiles > 0 ) | ||
| { | ||
| std::error_code ec; | ||
| if ( !std::filesystem::is_directory( sharedFolder, ec ) ) | ||
| if ( !std::filesystem::create_directories( sharedFolder, ec ) ) | ||
| return MR::unexpected( "Cannot create directories " + MR::utf8string( sharedFolder ) ); | ||
| } |
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.
i think we should move this logic inside Object::serialize function
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.
it can be done once with small refactoring #5240 (comment)
source/MRMesh/MRObjectSave.cpp
Outdated
| auto it = links.find( { node } ); | ||
| if ( it == links.end() ) | ||
| links[{ node }] = {}; |
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.
links.insert
da913d5 to
09af1e4
Compare
| // return shared models count | ||
| int collectLinks( const Object& rootObject, MapSharedObjects& links ) |
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.
detailed comment would be better
09af1e4 to
99313fb
Compare
No description provided.