Skip to content

Conversation

@pashem
Copy link
Contributor

@pashem pashem commented Oct 15, 2025

No description provided.

@pashem pashem requested a review from gorbovskoy-evg October 15, 2025 12:03
@pashem pashem force-pushed the 5238-de-serialization-of-objects-with-same-shared-model-mesh-support branch 2 times, most recently from f1e04d2 to 29e9bc8 Compare October 15, 2025 14:37
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;
Copy link
Contributor

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.

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 ) );
Copy link
Contributor

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?

if ( node->isAncillary() )
continue; // consider ancillary_ objects as temporary, not requiring saving

auto it = links.find( { node } );
Copy link
Contributor

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


/// Reads model from file
MRMESH_API virtual Expected<void> deserializeModel_( const std::filesystem::path& path, ProgressCallback progressCb = {} );
/// reads model from oter object
Copy link
Contributor

Choose a reason for hiding this comment

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

oter -> other, reads - > shares

[[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;
Copy link
Contributor

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


/// \}

struct KeyObjectModel
Copy link
Contributor

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?

Copy link
Contributor Author

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


struct LinkData
{
std::string link; // relative path (link) to shared model file
Copy link
Contributor

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

Comment on lines 63 to 66
// 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*>;
Copy link
Contributor

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?

Copy link
Contributor Author

@pashem pashem Oct 16, 2025

Choose a reason for hiding this comment

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

I don't understund

  1. 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)

Comment on lines 243 to 244
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;
Copy link
Contributor

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?

Copy link
Contributor Author

@pashem pashem Oct 16, 2025

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()

Comment on lines 249 to 250
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 );
Copy link
Contributor

Choose a reason for hiding this comment

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

same

Copy link
Contributor Author

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

}

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
Copy link
Contributor

@Grantim Grantim Oct 16, 2025

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
}

if ( !res.has_value() )
return res;
std::string link;
if ( !root["Link"].empty() )
Copy link
Contributor

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

Comment on lines 384 to 388
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
};
Copy link
Contributor

@Grantim Grantim Oct 16, 2025

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

Comment on lines 319 to 320
/// reads model from oter object
MRMESH_API virtual Expected<void> setModelFromObject_( const Object& other );
Copy link
Contributor

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

Comment on lines 279 to 288
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");
}
Copy link
Contributor

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?

Copy link
Contributor Author

@pashem pashem Oct 16, 2025

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?

Copy link
Contributor

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

Comment on lines 248 to 258
// 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 ) );
}
Copy link
Contributor

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

Copy link
Contributor

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)

Comment on lines 137 to 139
auto it = links.find( { node } );
if ( it == links.end() )
links[{ node }] = {};
Copy link
Contributor

Choose a reason for hiding this comment

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

links.insert

@pashem pashem force-pushed the 5238-de-serialization-of-objects-with-same-shared-model-mesh-support branch 2 times, most recently from da913d5 to 09af1e4 Compare October 16, 2025 23:15
Comment on lines 53 to 60
// return shared models count
int collectLinks( const Object& rootObject, MapSharedObjects& links )
Copy link
Contributor

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

@pashem pashem force-pushed the 5238-de-serialization-of-objects-with-same-shared-model-mesh-support branch from 09af1e4 to 99313fb Compare October 17, 2025 09:27
@pashem pashem merged commit 3f36c2b into master Oct 17, 2025
35 checks passed
@pashem pashem deleted the 5238-de-serialization-of-objects-with-same-shared-model-mesh-support branch October 17, 2025 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants