Commit ca0218a0 authored by T.J. Corona's avatar T.J. Corona Committed by Kitware Robot
Browse files

Merge topic 'refactor-delaunay-extension'

9c0af72b

 Refactor delaunay extension to facilitate code reuse.
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !527
parents 01bf3444 9c0af72b
set(source
TessellateFace.cxx
TriangulateFace.cxx)
io/ImportDelaunayMesh.cxx
io/ExportDelaunayMesh.cxx
operators/TessellateFace.cxx
operators/TriangulateFace.cxx)
set(headers
TessellateFace.h
TriangulateFace.h)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/TriangulateFace.sbt" delaunayOperatorXML)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/TessellateFace.sbt" delaunayOperatorXML)
io/ImportDelaunayMesh.h
io/ExportDelaunayMesh.h
operators/TessellateFace.h
operators/TriangulateFace.h)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/TriangulateFace.sbt" delaunayOperatorXML)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/TessellateFace.sbt" delaunayOperatorXML)
add_library(smtkDelaunayExt ${source})
target_link_libraries(smtkDelaunayExt
......
//=============================================================================
//
// 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/extension/delaunay/io/ExportDelaunayMesh.h"
#include "smtk/mesh/Collection.h"
#include "smtk/mesh/ExtractTessellation.h"
#include "smtk/mesh/MeshSet.h"
#include "Shape/Point.hh"
namespace smtk {
namespace extension {
namespace delaunay {
namespace io {
std::vector<Delaunay::Shape::Point> ExportDelaunayMesh::operator()
(const smtk::model::Loop& loop, smtk::mesh::CollectionPtr& collection) const
{
std::int64_t connectivityLength= -1;
std::int64_t numberOfCells = -1;
std::int64_t numberOfPoints = -1;
//query for all cells
smtk::mesh::PreAllocatedTessellation::determineAllocationLengths(
loop, collection, connectivityLength, numberOfCells, numberOfPoints);
std::vector<std::int64_t> conn( connectivityLength );
std::vector<float> fpoints(numberOfPoints * 3);
smtk::mesh::PreAllocatedTessellation ftess(&conn[0], &fpoints[0]);
ftess.disableVTKStyleConnectivity(true);
ftess.disableVTKCellTypes(true);
smtk::mesh::extractOrderedTessellation(loop, collection, ftess);
std::vector<Delaunay::Shape::Point> points;
for (std::size_t i=0;i<fpoints.size(); i+=3)
{
points.push_back(Delaunay::Shape::Point(fpoints[i], fpoints[i+1]));
}
// loops sometimes have a redundant point at the end. We need to remove it.
if (points.front() == points.back())
{
points.pop_back();
}
return points;
}
}
}
}
}
//=============================================================================
//
// 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.
//
//=============================================================================
#ifndef __smtk_extension_delaunay_io_ExportDelaunayMesh_h
#define __smtk_extension_delaunay_io_ExportDelaunayMesh_h
#include "smtk/extension/delaunay/Exports.h"
//forward declarers for Manager and Collection
#include "smtk/PublicPointerDefs.h"
namespace Delaunay {
namespace Shape {
class Point;
}
}
namespace smtk {
namespace model {
class Loop;
}
}
namespace smtk {
namespace extension {
namespace delaunay {
namespace io {
/**\brief Export from smtk into a Delaunay mesh
*
*/
class SMTKDELAUNAYEXT_EXPORT ExportDelaunayMesh
{
public:
ExportDelaunayMesh() {}
ExportDelaunayMesh(const ExportDelaunayMesh&) = delete;
ExportDelaunayMesh& operator=(const ExportDelaunayMesh&) = delete;
//Export a model loop with a mesh representation (likely constructed from
// smtk::io::modelToMesh) stored in the collection into a vector of Delaunay
// points.
std::vector<Delaunay::Shape::Point> operator()(
const smtk::model::Loop&, smtk::mesh::CollectionPtr&) const;
};
}
}
}
}
#endif
//=============================================================================
//
// 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/extension/delaunay/io/ImportDelaunayMesh.h"
#include "smtk/mesh/Collection.h"
#include "smtk/mesh/MeshSet.h"
#include "Mesh/Mesh.hh"
#include "Shape/Point.hh"
#include "Shape/Polygon.hh"
#include "Shape/PolygonUtilities.hh"
namespace smtk {
namespace extension {
namespace delaunay {
namespace io {
namespace {
template <typename Point, typename PointContainer>
std::size_t IndexOf(Point& point, const PointContainer& points)
{
return std::distance(points.begin(),
std::find(points.begin(), points.end(), point));
}
}
smtk::mesh::MeshSet
ImportDelaunayMesh::operator()(const Delaunay::Mesh::Mesh& mesh,
smtk::mesh::CollectionPtr collection) const
{
smtk::mesh::InterfacePtr iface = collection->interface();
smtk::mesh::AllocatorPtr alloc = iface->allocator();
smtk::mesh::Handle firstVertex = 0;
std::vector<double*> coordinateMemory;
if (!alloc->allocatePoints(mesh.GetVertices().size(),
firstVertex,
coordinateMemory))
{
return collection->createMesh(
smtk::mesh::CellSet(collection, smtk::mesh::HandleRange()));
}
std::size_t idx = 0;
for (auto& p : mesh.GetVertices())
{
idx = IndexOf(p, mesh.GetVertices());
coordinateMemory[0][idx] = p.x;
coordinateMemory[1][idx] = p.y;
coordinateMemory[2][idx] = 0.;
}
smtk::mesh::HandleRange createdCellIds;
smtk::mesh::Handle* connectivity;
if (!alloc->allocateCells(smtk::mesh::Triangle,
mesh.GetTriangles().size(),
smtk::mesh::verticesPerCell(smtk::mesh::Triangle),
createdCellIds,
connectivity))
{
return collection->createMesh(
smtk::mesh::CellSet(collection, smtk::mesh::HandleRange()));
}
idx = 0;
for (auto& t : mesh.GetTriangles())
{
connectivity[idx++] = firstVertex + IndexOf(t.AB().A(), mesh.GetVertices());
connectivity[idx++] = firstVertex + IndexOf(t.AB().B(), mesh.GetVertices());
connectivity[idx++] = firstVertex + IndexOf(t.AC().B(), mesh.GetVertices());
}
alloc->connectivityModified(createdCellIds,
smtk::mesh::verticesPerCell(smtk::mesh::Triangle),
connectivity);
return collection->createMesh(smtk::mesh::CellSet(collection,createdCellIds));
}
bool ImportDelaunayMesh::operator()(const Delaunay::Mesh::Mesh& mesh,
smtk::model::EntityRef& eRef) const
{
if (!eRef.isValid() || !eRef.isFace())
{
return false;
}
smtk::model::Tessellation* tess = eRef.resetTessellation();
tess->coords().resize(mesh.GetVertices().size()*3);
std::size_t index = 0;
double xyz[3];
for (auto& p : mesh.GetVertices())
{
index = IndexOf(p, mesh.GetVertices());
xyz[0] = p.x;
xyz[1] = p.y;
xyz[2] = 0.;
tess->setPoint(static_cast<int>(index), xyz);
}
for (auto& t : mesh.GetTriangles())
{
tess->addTriangle(static_cast<int>(IndexOf(t.AB().A(), mesh.GetVertices())),
static_cast<int>(IndexOf(t.AB().B(), mesh.GetVertices())),
static_cast<int>(IndexOf(t.AC().B(), mesh.GetVertices())));
}
auto bounds = Delaunay::Shape::Bounds(mesh.GetPerimeter());
const double bbox[6] = {bounds[0], bounds[1], bounds[2], bounds[3], 0., 0.};
eRef.setBoundingBox(bbox);
return true;
}
}
}
}
}
//=============================================================================
//
// 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.
//
//=============================================================================
#ifndef __smtk_extension_delaunay_io_ImportDelaunayMesh_h
#define __smtk_extension_delaunay_io_ImportDelaunayMesh_h
#include "smtk/extension/delaunay/Exports.h"
//forward declarers for Manager and Collection
#include "smtk/PublicPointerDefs.h"
namespace Delaunay {
namespace Mesh {
class Mesh;
}
}
namespace smtk {
namespace mesh {
class MeshSet;
}
}
namespace smtk {
namespace model {
class EntityRef;
}
}
namespace smtk {
namespace extension {
namespace delaunay {
namespace io {
/**\brief Import a Delaunay mesh into smtk.
*
* This functor converts Delaunay Meshes into smtk::mesh::MeshSets or into
* smtk::model::Tessellations.
*/
class SMTKDELAUNAYEXT_EXPORT ImportDelaunayMesh
{
public:
ImportDelaunayMesh() {}
ImportDelaunayMesh(const ImportDelaunayMesh&) = delete;
ImportDelaunayMesh& operator=(const ImportDelaunayMesh&) = delete;
//Import a Delaunay mesh into an existing collection.
smtk::mesh::MeshSet operator()(const Delaunay::Mesh::Mesh&,
smtk::mesh::CollectionPtr) const;
//Import a Delaunay mesh as a tessellation for an entity.
bool operator()(const Delaunay::Mesh::Mesh&,
smtk::model::EntityRef&) const;
};
}
}
}
}
#endif
//=============================================================================
//
// 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/extension/delaunay/operators/TessellateFace.h"
#include "smtk/extension/delaunay/io/ImportDelaunayMesh.h"
#include "smtk/extension/delaunay/io/ExportDelaunayMesh.h"
#include "smtk/io/ModelToMesh.h"
#include "smtk/mesh/Collection.h"
#include "smtk/mesh/ExtractTessellation.h"
#include "smtk/mesh/Manager.h"
#include "smtk/model/Edge.h"
#include "smtk/model/Face.h"
#include "smtk/model/FaceUse.h"
#include "smtk/model/Loop.h"
#include "Discretization/ConstrainedDelaunayMesh.hh"
#include "Discretization/ExcisePolygon.hh"
#include "Mesh/Mesh.hh"
#include "Shape/Point.hh"
#include "Shape/Polygon.hh"
#include "Shape/PolygonUtilities.hh"
#include <algorithm>
namespace smtk {
namespace model {
TessellateFace::TessellateFace()
{
}
bool TessellateFace::ableToOperate()
{
smtk::model::EntityRef eRef =
this->specification()->findModelEntity("face")->value();
return
this->Superclass::ableToOperate() &&
eRef.isValid() &&
eRef.isFace() &&
eRef.owningModel().isValid();
}
OperatorResult TessellateFace::operateInternal()
{
smtk::model::Face face =
this->specification()->findModelEntity("face")->
value().as<smtk::model::Face>();
smtk::io::ModelToMesh convert;
convert.setIsMerging(false);
smtk::mesh::CollectionPtr collection = convert(this->session()->meshManager(),
this->session()->manager());
// get the face use for the face
smtk::model::FaceUse fu = face.positiveUse();
// check if we have an exterior loop
smtk::model::Loops exteriorLoops = fu.loops();
if (exteriorLoops.size() == 0)
{
// if we don't have loops we are bailing out!
smtkErrorMacro(this->log(), "No loops associated with this face.");
return this->createResult(OPERATION_FAILED);
}
// the first loop is the exterior loop
smtk::model::Loop exteriorLoop = exteriorLoops[0];
// make a polygon from the points in the loop
smtk::extension::delaunay::io::ExportDelaunayMesh exportToDelaunayMesh;
std::vector<Delaunay::Shape::Point> points =
exportToDelaunayMesh(exteriorLoop, collection);
Delaunay::Shape::Polygon p(points);
// if the orientation is not ccw, flip the orientation
if (Delaunay::Shape::Orientation(p) != 1)
{
p = Delaunay::Shape::Polygon(points.rbegin(), points.rend());
}
// discretize the polygon
Delaunay::Discretization::ConstrainedDelaunayMesh discretize;
Delaunay::Mesh::Mesh mesh;
discretize(p, mesh);
// then we excise each inner loop within the exterior loop
Delaunay::Discretization::ExcisePolygon excise;
for (auto& loop : exteriorLoop.containedLoops())
{
std::vector<Delaunay::Shape::Point> points_sub =
exportToDelaunayMesh(loop, collection);
Delaunay::Shape::Polygon p_sub(points_sub);
// if the orientation is not ccw, flip the orientation
if (Delaunay::Shape::Orientation(p_sub) != 1)
{
p_sub = Delaunay::Shape::Polygon(points_sub.rbegin(), points_sub.rend());
}
excise(p_sub, mesh);
}
// remove the original collection
this->session()->meshManager()->removeCollection(collection);
// Use the delaunay mesh to retessellate the face
smtk::extension::delaunay::io::ImportDelaunayMesh importFromDelaunayMesh;
importFromDelaunayMesh(mesh, face);
OperatorResult result = this->createResult(OPERATION_SUCCEEDED);
this->addEntityToResult(result, face, MODIFIED);
result->findModelEntity("tess_changed")->setValue(face);
return result;
}
} // namespace model
} // namespace smtk
#include "smtk/extension/delaunay/Exports.h"
#include "smtk/extension/delaunay/TessellateFace_xml.h"
smtkImplementsModelOperator(
SMTKDELAUNAYEXT_EXPORT,
smtk::model::TessellateFace,
delaunay_tessellate_face,
"tessellate face",
TessellateFace_xml,
smtk::model::Session);
......@@ -9,7 +9,7 @@
// PURPOSE. See the above copyright notice for more information.
//
//=============================================================================
#include "smtk/extension/delaunay/TessellateFace.h"
#include "smtk/extension/delaunay/operators/TessellateFace.h"
#include "smtk/io/ModelToMesh.h"
......
......@@ -9,7 +9,10 @@
// PURPOSE. See the above copyright notice for more information.
//
//=============================================================================
#include "smtk/extension/delaunay/TriangulateFace.h"
#include "smtk/extension/delaunay/operators/TriangulateFace.h"
#include "smtk/extension/delaunay/io/ImportDelaunayMesh.h"
#include "smtk/extension/delaunay/io/ExportDelaunayMesh.h"
#include "smtk/io/ModelToMesh.h"
......@@ -31,104 +34,6 @@
#include <algorithm>
namespace {
std::vector<Delaunay::Shape::Point> pointsInLoop(
const smtk::model::Loop& loop, smtk::mesh::CollectionPtr& collection)
{
std::int64_t connectivityLength= -1;
std::int64_t numberOfCells = -1;
std::int64_t numberOfPoints = -1;
//query for all cells
smtk::mesh::PreAllocatedTessellation::determineAllocationLengths(
loop, collection, connectivityLength, numberOfCells, numberOfPoints);
std::vector<std::int64_t> conn( connectivityLength );
std::vector<float> fpoints(numberOfPoints * 3);
smtk::mesh::PreAllocatedTessellation ftess(&conn[0], &fpoints[0]);
ftess.disableVTKStyleConnectivity(true);
ftess.disableVTKCellTypes(true);
smtk::mesh::extractOrderedTessellation(loop, collection, ftess);
std::vector<Delaunay::Shape::Point> points;
for (std::size_t i=0;i<fpoints.size(); i+=3)
{
points.push_back(Delaunay::Shape::Point(fpoints[i], fpoints[i+1]));
}
// loops sometimes have a redundant point at the end. We need to remove it.
if (points.front() == points.back())
{
points.pop_back();
}
return points;
}
template <typename Point, typename PointContainer>
std::size_t IndexOf(Point& point, const PointContainer& points)
{
return std::distance(points.begin(),
std::find(points.begin(), points.end(), point));
}
smtk::mesh::HandleRange ImportDelaunayMesh(const Delaunay::Mesh::Mesh& mesh,
smtk::mesh::CollectionPtr collection)
{
smtk::mesh::InterfacePtr iface = collection->interface();
smtk::mesh::AllocatorPtr alloc = iface->allocator();
smtk::mesh::Handle firstVertex = 0;
std::vector<double*> coordinateMemory;
if (!alloc->allocatePoints(mesh.GetVertices().size(),
firstVertex,
coordinateMemory))
{
return smtk::mesh::HandleRange();
}
std::size_t index = 0;
for (auto& p : mesh.GetVertices())
{
index = IndexOf(p, mesh.GetVertices());
coordinateMemory[0][index] = p.x;
coordinateMemory[1][index] = p.y;
coordinateMemory[2][index] = 0.;
}
smtk::mesh::HandleRange createdCellIds;
smtk::mesh::Handle* connectivity;
if (!alloc->allocateCells(smtk::mesh::Triangle,
mesh.GetTriangles().size(),
smtk::mesh::verticesPerCell(smtk::mesh::Triangle),
createdCellIds,
connectivity))
{