Commit ce5846d3 authored by Robert Maynard's avatar Robert Maynard

Fix a bug where merging pure vertices mesh caused invalid point locations.

parent 32f32314
Pipeline #7485 passed with stage
......@@ -72,7 +72,7 @@ MergeMeshVertices::~MergeMeshVertices()
++i)
{
Range tmp;
rval = mbImpl->get_entities_by_handle(*i, entities, /*recursive*/ true);
rval = mbImpl->get_entities_by_handle(*i, tmp, /*recursive*/ true);
if (MB_SUCCESS != rval)
{
return rval;
......@@ -80,10 +80,9 @@ MergeMeshVertices::~MergeMeshVertices()
entities.insert(tmp.begin(), tmp.end());
}
Range sets= entities.subset_by_type(MBENTITYSET);
entities= ::moab::subtract(entities, sets);
Range verts;
rval = mbImpl->get_connectivity(entities, verts);;
rval = mbImpl->get_connectivity(entities, verts);
if (MB_SUCCESS != rval)
{
return rval;
......@@ -99,19 +98,32 @@ MergeMeshVertices::~MergeMeshVertices()
}
// find matching vertices, mark them
rval = find_merged_to(tree_root, kd, mbMergeTag);;
rval = find_merged_to(tree_root, kd, mbMergeTag);
if (MB_SUCCESS != rval)
{
return rval;
}
rval = perform_merge(mbMergeTag);;
rval = perform_merge(mbMergeTag);
if (MB_SUCCESS != rval)
{
return rval;
}
//currently skipping higher dimensions
rval = correct_vertex_merge(mbMergeTag, meshsets);
if (MB_SUCCESS != rval)
{
return rval;
}
//delete the deadEnts
mbImpl->delete_entities(deadEnts);
rval = merge_higher_dimensions(entities);
if (MB_SUCCESS != rval)
{
return rval;
}
return MB_SUCCESS;
}
......@@ -297,17 +309,151 @@ MergeMeshVertices::~MergeMeshVertices()
assert(merge_tag_val[i]);
if (MBVERTEX==mbImpl->type_from_handle(merge_tag_val[i]) )
mergedToVertices.insert(merge_tag_val[i]);
result = mbImpl->merge_entities(merge_tag_val[i], *rit, false, false);
if (MB_SUCCESS != result)
{
return result;
}
}
result = mbImpl->delete_entities(deadEnts);
return result;
}
//----------------------------------------------------------------------------
//now before we delete the entities,
//we need to make sure that any mesh that is losing an explicit vertex
//has it replaced with the merged vertex, this isn't handled by perform_merge
//as it only does dim > 0
::moab::ErrorCode MergeMeshVertices::correct_vertex_merge(::moab::Tag merged_to,
const smtk::mesh::HandleRange& meshsets)
{
using ::moab::EntityHandle;
using ::moab::ErrorCode;
using ::moab::Range;
using ::moab::MBVERTEX;
using ::moab::MB_SUCCESS;
using ::moab::MB_FAILURE;
for(smtk::mesh::HandleRange::const_iterator i = meshsets.begin();
i != meshsets.end();
++i)
{
Range entitiesVerts;
mbImpl->get_entities_by_dimension(*i, 0 /*dimension*/, entitiesVerts, /*recursive*/ true);
//determine if we have a vert which is going deleted
Range vertsToDelete = ::moab::intersect(deadEnts, entitiesVerts);
if(!vertsToDelete.empty())
{
std::vector<EntityHandle> merge_tag_val(vertsToDelete.size());
mbImpl->tag_get_data(mbMergeTag, vertsToDelete, &merge_tag_val[0]);
Range::iterator rit;
std::size_t j;
for (rit = vertsToDelete.begin(), j = 0; rit != vertsToDelete.end(); rit++, j++)
{
//now we add these entities to the new meshset
EntityHandle t = merge_tag_val[j];
mbImpl->add_entities(*i, &t, 1);
}
mbImpl->remove_entities(*i, vertsToDelete);
}
}
return MB_SUCCESS;
}
//----------------------------------------------------------------------------
//Determine which higher dimensional entities should be merged
::moab::ErrorCode MergeMeshVertices::merge_higher_dimensions(::moab::Range &elems)
{
using ::moab::EntityHandle;
using ::moab::ErrorCode;
using ::moab::Range;
using ::moab::MBVERTEX;
using ::moab::MB_SUCCESS;
using ::moab::MB_FAILURE;
// apply a different strategy
// look at the vertices that were merged to, earlier, and find all entities adjacent to them
// elems (input) are used just for initial connectivity
ErrorCode result;
Range verts;
result = mbImpl->get_connectivity(elems, verts);
verts.merge(elems.subset_by_dimension(0)); //don't forget these
if (MB_SUCCESS!=result)
return result;
// all higher dim entities that will be merged will be connected to the vertices that were
// merged earlier; we will look at these vertices only
Range vertsOfInterest=intersect(this->mergedToVertices, verts);
//Go through each dimension
Range possibleEntsToMerge, conn, matches, moreDeadEnts;
for (int dim = 1; dim < 3; dim++)
{
moreDeadEnts.clear();
possibleEntsToMerge.clear();
result = mbImpl->get_adjacencies(vertsOfInterest,
dim, false, possibleEntsToMerge,
::moab::Interface::UNION);
if (MB_SUCCESS!=result)
return result;
//Go through each possible entity and see if it shares vertices with another entity of same dimension
for (Range::iterator pit = possibleEntsToMerge.begin();
pit != possibleEntsToMerge.end(); pit++)
{
EntityHandle eh=*pit;//possible entity to be matched
conn.clear();
//Get the vertices connected to it in a range
if(mbImpl->type_from_handle(eh) != MBVERTEX)
{
result = mbImpl->get_connectivity(&eh, 1, conn);
}
else
{
conn.insert(eh);
result = MB_SUCCESS;
}
if (MB_SUCCESS!=result)
return result;
matches.clear();
// now retrieve all entities connected to all conn vertices
result = mbImpl->get_adjacencies(conn, dim, false, matches,
::moab::Interface::INTERSECT);
if (MB_SUCCESS!=result)
return result;
if (matches.size() > 1)
{
for (Range::iterator matchIt = matches.begin();
matchIt != matches.end(); matchIt++)
{
EntityHandle to_remove=*matchIt;
if (to_remove != eh)
{
moreDeadEnts.insert(to_remove);
result = mbImpl->merge_entities(eh, to_remove, false, false);
if (result != MB_SUCCESS)
return result;
possibleEntsToMerge.erase(to_remove);
}
}
}
}
//Delete the entities of dimension dim
result = mbImpl->delete_entities(moreDeadEnts);
if (result != MB_SUCCESS)
return result;
}
return MB_SUCCESS;
}
} // namespace moab
} // namespace mesh
} // namespace smtk
......@@ -39,6 +39,14 @@ private:
//- perform the actual merge
::moab::ErrorCode perform_merge(::moab::Tag merged_to);
//- correct any occurrences of vertices inside a mesh being deleted and
// the replacement vertex not already being an entity of that mesh
::moab::ErrorCode correct_vertex_merge(::moab::Tag merged_to,
const smtk::mesh::HandleRange& meshsets);
//Identify higher dimension to be merged
::moab::ErrorCode merge_higher_dimensions(::moab::Range &elems);
::moab::Interface *mbImpl;
//- the tag pointing to the entity to which an entity will be merged
......
......@@ -29,6 +29,7 @@ set(unit_tests_which_require_data
UnitTestExportMesh3DM.cxx
UnitTestLoadMesh.cxx
UnitTestReclassifyEdges.cxx
UnitTestMergeContactPoints.cxx
UnitTestMeshSet.cxx
UnitTestModelToMesh2D.cxx
UnitTestPointConnectivity.cxx
......
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#include "smtk/io/ModelToMesh.h"
#include "smtk/io/ImportJSON.h"
#include "smtk/io/WriteMesh.h"
#include "smtk/mesh/Collection.h"
#include "smtk/mesh/Manager.h"
#include "smtk/model/Manager.h"
#include "smtk/model/Volume.h"
#include "smtk/model/EntityIterator.h"
#include "smtk/model/testing/cxx/helpers.h"
#include "smtk/mesh/testing/cxx/helpers.h"
#include <sstream>
#include <fstream>
//force to use filesystem version 3
#define BOOST_FILESYSTEM_VERSION 3
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
namespace
{
//SMTK_DATA_DIR is a define setup by cmake
std::string data_root = SMTK_DATA_DIR;
//----------------------------------------------------------------------------
void create_simple_mesh_model( smtk::model::ManagerPtr mgr )
{
std::string file_path(data_root);
file_path += "/smtk/test2D.json";
std::ifstream file(file_path.c_str());
std::string json(
(std::istreambuf_iterator<char>(file)),
(std::istreambuf_iterator<char>()));
//we should load in the test2D.json file as an smtk to model
smtk::io::ImportJSON::intoModelManager(json.c_str(), mgr);
mgr->assignDefaultNames();
file.close();
}
//----------------------------------------------------------------------------
smtk::mesh::MeshSet make_MeshPoint(smtk::mesh::CollectionPtr collection,
double x, double y, double z)
{
smtk::mesh::InterfacePtr interface = collection->interface();
smtk::mesh::AllocatorPtr allocator = interface->allocator();
smtk::mesh::Handle vertexHandle;
std::vector<double*> coords;
allocator->allocatePoints(1, vertexHandle, coords);
coords[0][0] = x;
coords[1][0] = y;
coords[2][0] = z;
smtk::mesh::HandleRange meshCells;
meshCells.insert(vertexHandle);
smtk::mesh::CellSet cellsForMesh(collection, meshCells);
smtk::mesh::MeshSet result = collection->createMesh(cellsForMesh);
return result;
}
//----------------------------------------------------------------------------
void verify_simple_merge()
{
smtk::mesh::ManagerPtr meshManager = smtk::mesh::Manager::create();
smtk::model::ManagerPtr modelManager = smtk::model::Manager::create();
create_simple_mesh_model(modelManager);
smtk::io::ModelToMesh convert;
smtk::mesh::CollectionPtr c = convert(meshManager,modelManager);
test( c->isValid(), "collection should be valid");
//make sure merging points works properly
smtk::mesh::PointSet points = c->points( );
test( points.size() == 88, "Should be exactly 88 points in the original mesh");
c->meshes().mergeCoincidentContactPoints();
points = c->points( );
test( points.size() == 32, "After merging of identical points we should have 32");
//verify that after merging points we haven't deleted any of the cells
//that represent a model vert
smtk::mesh::CellSet vert_cells = c->cells( smtk::mesh::Dims0 );
test( vert_cells.size() == 7 );
}
//----------------------------------------------------------------------------
void verify_complex_merge()
{
smtk::mesh::ManagerPtr meshManager = smtk::mesh::Manager::create();
smtk::model::ManagerPtr modelManager = smtk::model::Manager::create();
create_simple_mesh_model(modelManager);
smtk::io::ModelToMesh convert;
smtk::mesh::CollectionPtr c = convert(meshManager,modelManager);
test( c->isValid(), "collection should be valid");
//add a new mesh which is a single point very close to 0,2,0
smtk::mesh::MeshSet newMeshPoint = make_MeshPoint(c, 0.0, 2.0, 0.0 );
//make sure merging points works properly
smtk::mesh::PointSet points = c->points( );
test( points.size() == 89, "should be 89 points before merge");
//failing to merge this point into the other points
c->meshes().mergeCoincidentContactPoints();
test( c->points().size() == 32, "After merging of identical points we should have 32");
//verify the point is merged properly
std::vector<double> p(3);
newMeshPoint.points().get(&p[0]);
test(p[0] == 0); test(p[1] == 2.0); test(p[2] == 0);
}
}
//----------------------------------------------------------------------------
int UnitTestMergeContactPoints(int, char** const)
{
// verify_simple_merge();
verify_complex_merge();
return 0;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment