42 #include <boost/filesystem.hpp> 51 std::shared_ptr<std::vector<T>> arr_;
54 explicit VectorCapsule(std::vector<T>&& arr)
55 : arr_(
std::make_shared<
std::vector<T>>(
std::move(arr)))
58 ~VectorCapsule() =
default;
59 void operator()(
void*) {}
68 float maxChunkOverlap,
76 std::vector<std::string>{layer},
82 float maxChunkOverlap,
84 std::vector<std::string> layers,
89 if (meshes.size() != layers.size())
91 std::cerr <<
lvr2::timestamp <<
"Number of meshes and layers do not match: \n" 92 <<
"Num meshes: " << meshes.size() <<
"\n" 93 <<
"Num layers: " << layers.size() << std::endl;
99 for (
size_t i = 0; i < meshes.size(); ++i)
104 for (
size_t i = 0; i < meshes.size(); ++i)
106 buildChunks(meshes[i], maxChunkOverlap, savePath, layers[i]);
117 std::vector<std::string> attributeList;
120 bool isChunkFound =
false;
128 boost::optional<MeshBufferPtr> requestedChunk
129 = getChunk<MeshBufferPtr>(layer, x, y, z);
132 chunkPtr = requestedChunk.get();
141 for (
auto channelIterator = chunkPtr->begin(); channelIterator != chunkPtr->end();
144 attributeList.push_back(channelIterator->first);
147 return attributeList;
151 std::unordered_map<std::size_t, MeshBufferPtr>& chunks,
168 = (adjustedArea.getMax() - adjustedArea.getMin()) /
getChunkSize();
169 for (std::size_t i = 0; i < maxSteps.x; ++i)
171 for (std::size_t j = 0; j < maxSteps.y; ++j)
173 for (std::size_t k = 0; k < maxSteps.z; ++k)
177 size_t cellIndex =
hashValue(cellCoord.
x, cellCoord.
y, cellCoord.
z);
185 boost::optional<MeshBufferPtr> loadedChunk
186 = getChunk<MeshBufferPtr>(layer, cellCoord.
x, cellCoord.
y, cellCoord.
z);
193 chunks.insert({cellIndex, *loadedChunk});
204 std::unordered_map<std::size_t, MeshBufferPtr> chunks;
220 = (adjustedArea.getMax() - adjustedArea.getMin()) /
getChunkSize();
221 for (std::size_t i = 0; i < maxSteps.x; ++i)
223 for (std::size_t j = 0; j < maxSteps.y; ++j)
225 for (std::size_t k = 0; k < maxSteps.z; ++k)
229 size_t cellIndex =
hashValue(cellCoord.
x, cellCoord.
y, cellCoord.
z);
231 boost::optional<MeshBufferPtr> loadedChunk
232 = getChunk<MeshBufferPtr>(layer, cellCoord.
x, cellCoord.
y, cellCoord.
z);
237 "area/" + std::to_string(cellIndex) +
".ply");
238 chunks.insert({cellIndex, *loadedChunk});
243 std::cout <<
"Extracted " << chunks.size() <<
" Chunks" << std::endl;
245 std::vector<float> areaDuplicateVertices;
246 std::vector<std::unordered_map<std::size_t, std::size_t>> areaVertexIndices;
247 std::vector<float> areaUniqueVertices;
248 for (
auto chunkIt = chunks.begin(); chunkIt != chunks.end(); ++chunkIt)
251 FloatChannel chunkVertices = *(chunk->getChannel<
float>(
"vertices"));
252 std::size_t numDuplicates = *chunk->getAtomic<
unsigned int>(
"num_duplicates");
253 std::size_t numVertices = chunk->numVertices();
254 std::unordered_map<std::size_t, std::size_t> chunkVertexIndices;
256 if (numVertices == 0)
261 if ((chunkIt == chunks.begin() || areaDuplicateVertices.empty()) && numDuplicates > 0)
263 areaDuplicateVertices.insert(areaDuplicateVertices.end(),
265 chunkVertices.
dataPtr().get() + (numDuplicates * 3));
268 for (std::size_t i = 0; i < numDuplicates; ++i)
270 const size_t areaDuplicateVerticesSize = areaDuplicateVertices.size();
273 for (std::size_t j = 0; j < areaDuplicateVerticesSize / 3; ++j)
275 if ((areaDuplicateVertices[j * 3] == chunkVertices[i][0])
276 && (areaDuplicateVertices[j * 3 + 1] == chunkVertices[i][1])
277 && (areaDuplicateVertices[j * 3 + 2] == chunkVertices[i][2]))
280 chunkVertexIndices.insert({i, j});
287 areaDuplicateVertices.push_back(chunkVertices[i][0]);
288 areaDuplicateVertices.push_back(chunkVertices[i][1]);
289 areaDuplicateVertices.push_back(chunkVertices[i][2]);
291 chunkVertexIndices.insert({i, areaDuplicateVertices.size() / 3 - 1});
295 areaUniqueVertices.insert(areaUniqueVertices.end(),
296 chunkVertices.
dataPtr().get() + (numDuplicates * 3),
297 (chunkVertices.
dataPtr().get() + (numVertices * 3)));
299 areaVertexIndices.push_back(chunkVertexIndices);
302 std::vector<unsigned int> areaFaceIndices;
303 const std::size_t staticFaceIndexOffset = areaDuplicateVertices.size() / 3;
304 std::size_t dynFaceIndexOffset = 0;
305 auto areaVertexIndicesIt = areaVertexIndices.begin();
306 for (
auto chunkIt = chunks.begin(); chunkIt != chunks.end(); ++chunkIt)
309 indexArray chunkFaceIndices = chunk->getFaceIndices();
310 std::size_t numDuplicates = *chunk->getAtomic<
unsigned int>(
"num_duplicates");
311 std::size_t numVertices = chunk->numVertices();
312 std::size_t numFaces = chunk->numFaces();
313 std::size_t faceIndexOffset = staticFaceIndexOffset - numDuplicates + dynFaceIndexOffset;
315 for (std::size_t i = 0; i < numFaces * 3; ++i)
317 std::size_t oldIndex = chunkFaceIndices[i];
318 auto it = (*areaVertexIndicesIt).find(oldIndex);
319 if (it != (*areaVertexIndicesIt).end())
321 areaFaceIndices.push_back(it->second);
325 areaFaceIndices.push_back(oldIndex + faceIndexOffset);
328 dynFaceIndexOffset += (numVertices - numDuplicates);
329 ++areaVertexIndicesIt;
332 std::cout <<
"combine vertices" << std::endl;
333 std::cout <<
"Duplicates: " << areaDuplicateVertices.size() / 3 << std::endl;
334 std::cout <<
"Unique: " << areaUniqueVertices.size() / 3 << std::endl;
335 areaDuplicateVertices.insert(
336 areaDuplicateVertices.end(), areaUniqueVertices.begin(), areaUniqueVertices.end());
338 std::size_t areaVertexNum = areaDuplicateVertices.size() / 3;
339 float* tmpVertices = areaDuplicateVertices.data();
341 =
floatArr(tmpVertices, VectorCapsule<float>(std::move(areaDuplicateVertices)));
343 std::size_t faceIndexNum = areaFaceIndices.size() / 3;
344 auto* tmpFaceIndices = areaFaceIndices.data();
346 =
indexArray(tmpFaceIndices, VectorCapsule<unsigned int>(std::move(areaFaceIndices)));
349 areaMeshPtr->setVertices(vertexArr, areaVertexNum);
350 areaMeshPtr->setFaceIndices(faceIndexArr, faceIndexNum);
352 for (
auto chunkIt = chunks.begin(); chunkIt != chunks.end(); ++chunkIt)
355 for (
auto elem : *chunk)
357 if (elem.first !=
"vertices" && elem.first !=
"face_indices" 358 && elem.first !=
"num_duplicates")
360 if (areaMeshPtr->find(elem.first) == areaMeshPtr->end())
363 if (elem.second.is_type<
unsigned char>())
365 areaMeshPtr->template addChannel<unsigned char>(
366 extractChannelOfArea<unsigned char>(chunks,
368 staticFaceIndexOffset,
369 areaMeshPtr->numVertices(),
370 areaMeshPtr->numFaces(),
374 else if (elem.second.is_type<
unsigned int>())
376 areaMeshPtr->template addChannel<unsigned int>(
377 extractChannelOfArea<unsigned int>(chunks,
379 staticFaceIndexOffset,
380 areaMeshPtr->numVertices(),
381 areaMeshPtr->numFaces(),
385 else if (elem.second.is_type<
float>())
387 areaMeshPtr->template addChannel<float>(
388 extractChannelOfArea<float>(chunks,
390 staticFaceIndexOffset,
391 areaMeshPtr->numVertices(),
392 areaMeshPtr->numFaces(),
401 std::cout <<
"Vertices: " << areaMeshPtr->numVertices()
402 <<
", Faces: " << areaMeshPtr->numFaces() << std::endl;
410 const std::map<std::string, FilterFunction>
filter,
417 std::vector<bool> vertexFilter(areaMesh->numVertices(),
true);
418 std::vector<bool> faceFilter(areaMesh->numFaces(),
true);
419 std::size_t numVertices = areaMesh->numVertices();
420 std::size_t numFaces = areaMesh->numFaces();
422 for (
auto channelFilter : filter)
424 if (areaMesh->find(channelFilter.first) != areaMesh->end())
427 #pragma omp parallel for 428 for (std::size_t i = 0; i < channel.
numElements(); i++)
430 if (channel.
numElements() == areaMesh->numVertices())
432 if (vertexFilter[i] ==
true)
434 vertexFilter[i] = channelFilter.second(channel, i);
435 if (vertexFilter[i] ==
false)
441 else if (channel.
numElements() == areaMesh->numFaces())
443 if (faceFilter[i] ==
true)
445 faceFilter[i] = channelFilter.second(channel, i);
446 if (faceFilter[i] ==
false)
457 IndexChannel facesChannel = *areaMesh->getIndexChannel(
"face_indices");
458 for (std::size_t i = 0; i < areaMesh->numFaces(); i++)
460 if (faceFilter[i] ==
true)
462 for (std::size_t j = 0; j < facesChannel.
width(); j++)
464 if (vertexFilter[facesChannel[i][j]] ==
false)
466 faceFilter[i] =
false;
475 std::vector<std::size_t> vertexIndexMapping(areaMesh->numVertices(), 0);
476 std::size_t tmpIndex = 0;
477 for (std::size_t i = 0; i < areaMesh->numVertices(); i++)
479 if (vertexFilter[i] ==
true)
481 vertexIndexMapping[i] = tmpIndex;
489 for (
auto& channel : *areaMesh)
493 if (channel.second.is_type<
unsigned char>())
495 channel.second = applyChannelFilter<unsigned char>(
496 vertexFilter, faceFilter, numVertices, numFaces, areaMesh, channel.second);
498 else if (channel.second.is_type<
unsigned int>())
500 channel.second = applyChannelFilter<unsigned int>(
501 vertexFilter, faceFilter, numVertices, numFaces, areaMesh, channel.second);
503 else if (channel.second.is_type<
float>())
505 channel.second = applyChannelFilter<float>(
506 vertexFilter, faceFilter, numVertices, numFaces, areaMesh, channel.second);
513 facesChannel = *areaMesh->getIndexChannel(
"face_indices");
514 for (std::size_t i = 0; i < areaMesh->numFaces(); i++)
516 for (std::size_t j = 0; j < facesChannel.width(); j++)
518 facesChannel[i][j] = vertexIndexMapping[facesChannel[i][j]];
528 FloatChannel vertices = mesh->getFloatChannel(
"vertices").get();
529 for (
unsigned int i = 0; i < vertices.
numElements(); i++)
539 std::shared_ptr<std::unordered_map<unsigned int, unsigned int>> splitVertices,
540 std::shared_ptr<std::unordered_map<unsigned int, unsigned int>> splitFaces)
545 while (iterator != halfEdgeMesh->edgesEnd())
548 std::array<VertexHandle, 2> vertices = halfEdgeMesh->getVerticesOfEdge(*iterator);
549 for (
unsigned int i = 0; i <= 1; i++)
554 bool isLargeEdge =
false;
557 for (
unsigned int axis = 0; axis < 3; axis++)
560 float referenceVertexKey = halfEdgeMesh->getVertexPosition(referenceVertex)[axis];
561 float comparedVertexKey = halfEdgeMesh->getVertexPosition(comparedVertex)[axis];
565 if (fabs(referenceVertexKey - comparedVertexKey) > 2 *
getChunkSize())
578 if (referenceVertexKey < comparedVertexKey)
584 if (referenceVertexKey - chunkBorder < 0 && comparedVertexKey - chunkBorder >= 0
585 && chunkBorder - referenceVertexKey > overlapRatio *
getChunkSize()
586 && comparedVertexKey - chunkBorder > overlapRatio *
getChunkSize())
591 else if (referenceVertexKey - chunkBorder >= 0
592 && comparedVertexKey - chunkBorder < 0
593 && referenceVertexKey - chunkBorder > overlapRatio *
getChunkSize()
594 && chunkBorder - comparedVertexKey > overlapRatio *
getChunkSize())
603 std::array<OptionalFaceHandle, 2> faces = halfEdgeMesh->getFacesOfEdge(*iterator);
606 unsigned int faceIndex = halfEdgeMesh->nextFaceIndex();
609 unsigned int face = faces[0].unwrap().idx();
610 while (splitFaces->find(face) != splitFaces->end())
612 face = splitFaces->at(face);
614 splitFaces->insert({faceIndex, face});
619 unsigned int face = faces[1].unwrap().idx();
620 while (splitFaces->find(face) != splitFaces->end())
622 face = splitFaces->at(face);
624 splitFaces->insert({faceIndex, face});
627 unsigned int vertex = referenceVertex.
idx();
628 while (splitVertices->find(vertex) != splitVertices->end())
630 vertex = splitVertices->at(vertex);
632 splitVertices->insert({halfEdgeMesh->nextVertexIndex(), vertex});
635 float cutRatio = 0.5;
637 = halfEdgeMesh->getVertexPosition(referenceVertex) * cutRatio
638 + halfEdgeMesh->getVertexPosition(comparedVertex) * (1 - cutRatio);
640 halfEdgeMesh->splitVertex(*iterator,
642 halfEdgeMesh->getVertexPosition(referenceVertex),
653 float maxChunkOverlap,
654 std::string savePath,
660 std::shared_ptr<HalfEdgeMesh<BaseVector<float>>> halfEdgeMesh
661 = std::shared_ptr<HalfEdgeMesh<BaseVector<float>>>(
665 std::shared_ptr<std::unordered_map<unsigned int, unsigned int>> splitVertices(
666 new std::unordered_map<unsigned int, unsigned int>);
667 std::shared_ptr<std::unordered_map<unsigned int, unsigned int>> splitFaces(
668 new std::unordered_map<unsigned int, unsigned int>);
671 cutLargeFaces(halfEdgeMesh, maxChunkOverlap, splitVertices, splitFaces);
674 std::shared_ptr<std::unordered_map<unsigned int, std::vector<std::weak_ptr<ChunkBuilder>>>>
675 vertexUse(
new std::unordered_map<
unsigned int, std::vector<std::weak_ptr<ChunkBuilder>>>());
692 for (
size_t i = 0; i < halfEdgeMesh->numFaces(); i++)
696 size_t hash =
hashValue(cellCorrdinate.
x, cellCorrdinate.
y, cellCorrdinate.
z);
698 chunkBuilders[hash]->addFace(*iterator);
712 if (chunkBuilders[hash]->numFaces() > 0)
718 = chunkBuilders[hash]->buildMesh(mesh, splitVertices, splitFaces);
726 setChunk<MeshBufferPtr>(layer, i, j, k, chunkMeshPtr);
728 chunkBuilders[hash] =
nullptr;
738 return (
mesh->getVertexPositionsOfFace(handle)[0] +
mesh->getVertexPositionsOfFace(handle)[1]
739 +
mesh->getVertexPositionsOfFace(handle)[2])
747 static_cast<int>(tmpVec.
x), static_cast<int>(tmpVec.
y),
static_cast<int>(tmpVec.
z));
768 if (loadChunk<MeshBufferPtr>(layer, i, j, k))
776 std::cout <<
"loaded " << numLoaded <<
" chunks from hdf5-file." << std::endl;
void buildChunks(MeshBufferPtr mesh, float maxChunkOverlap, std::string savePath, std::string layer=std::string("mesh"))
buildChunks builds chunks from an original mesh
A wrapper for the MeshHandleIterator to save beloved future programmers from dereferencing too much <...
BaseVector< int > getChunkMaxChunkIndex() const
returns the maximum chunk ids
const BoundingBox< BaseVector< float > > & getBoundingBox() const
float getChunkSize() const
Handle to access vertices of the mesh.
std::shared_ptr< MeshBuffer > MeshBufferPtr
void expand(T v)
Expands the bounding box if the given Vector v} is outside the current volume.
BaseVecT getMin() const
Returns the lower left coordinates.
static Timestamp timestamp
A global time stamp object for program runtime measurement.
MeshBufferPtr extractArea(const BoundingBox< BaseVector< float >> &area, std::string layer=std::string("mesh"))
extractArea creates and returns MeshBufferPtr of merged chunks for given area.
std::shared_ptr< ChunkBuilder > ChunkBuilderPtr
std::size_t hashValue(int i, int j, int k) const
Calculates the hash value for the given index triple.
const BaseVector< std::size_t > & getChunkAmount() const
const DataPtr dataPtr() const
A dynamic bounding box class.
void setBoundingBox(const BoundingBox< BaseVector< float >> boundingBox)
sets the bounding box in this container and in persistend storage
size_t numElements() const
std::vector< std::string > getChannelsFromMesh(std::string layer=std::string("mesh"))
Get all existing channels from mesh.
ChunkManager(MeshBufferPtr meshes, float chunksize, float maxChunkOverlap, std::string savePath, std::string layer=std::string("mesh"), size_t cacheSize=200)
ChunkManager creates chunks from an original mesh.
BaseVector< float > getFaceCenter(std::shared_ptr< HalfEdgeMesh< BaseVector< float >>> mesh, const FaceHandle &handle) const
getFaceCenter gets the center point for a given face
void initBoundingBox(MeshBufferPtr mesh)
initBoundingBox calculates a bounding box of the original mesh
BaseVector< int > getChunkMinChunkIndex() const
returns the minimum chunk ids
void loadAllChunks(std::string layer=std::string("mesh"))
Loads all chunks into the ChunkHashGrid. DEBUG – Only used for testing, but might be useful for smal...
boost::shared_array< unsigned int > indexArray
boost::shared_array< float > floatArr
Half-edge data structure implementing the BaseMesh interface.
void filter(lvr2::PointBufferPtr &cloud, lvr2::indexArray &inlier, size_t j)
void setChunkSize(float chunkSize)
sets chunk size in this container and in persistent storage
BaseVecT getMax() const
Returns the upper right coordinates.
std::shared_ptr< Model > ModelPtr
BaseVector< int > getCellCoordinates(const BaseVector< float > &vec) const
find corresponding grid cell of given point
void cutLargeFaces(std::shared_ptr< HalfEdgeMesh< BaseVector< float >>> halfEdgeMesh, float overlapRatio, std::shared_ptr< std::unordered_map< unsigned int, unsigned int >> splitVertices, std::shared_ptr< std::unordered_map< unsigned int, unsigned int >> splitFaces)
cutLargeFaces cuts a face if it is too large
The MeshBuffer Mesh representation for I/O modules.
size_t numElements() const
static void saveModel(ModelPtr m, std::string file)
Handle to access faces of the mesh.