Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
AlignPlugin.cc
1 
8 
9 #include <Eigen/Dense>
10 
11 #include "AlignPlugin.hh"
12 
14  : sourceMeshCombo_()
15  , targetMeshCombo_()
16  , doScaleCheckBox_()
17  , alignMeshesButton_()
18  , sourceId_(-1)
19  , targetId_(-1)
20 {
21 }
22 
23 void AlignPlugin::slotAlignMeshes()
24 {
25  using namespace Eigen;
26 
27  BaseObjectData *sourceObject = NULL;
28  if (!PluginFunctions::getObject(sourceId_, sourceObject)) {
29  emit log(LOGERR, tr("Cannot get source mesh object %1").arg(sourceId_));
30  return;
31  }
32 
33  BaseObjectData *targetObject = NULL;
34  if (!PluginFunctions::getObject(targetId_, targetObject)) {
35  emit log(LOGERR, tr("Cannot get target mesh object %1").arg(targetId_));
36  return;
37  }
38 
39  Vector3d sc;
40  Matrix3d spd;
41  if (!computePCA(getPoints(sourceObject), sc, spd)) {
42  emit log(LOGERR, "PCA of source object failed");
43  return;
44  }
45 
46  Vector3d tc;
47  Matrix3d tpd;
48  Point_container targetPoints = getPoints(targetObject);
49  if (!computePCA(targetPoints, tc, tpd)) {
50  emit log(LOGERR, "PCA of target object failed");
51  return;
52  }
53 
54  Affine3d t = spd.transpose() * Translation3d(-sc);
55  transformObject(sourceObject, t);
56 
57  t = tpd.transpose() * Translation3d(-tc);
58  transformPoints(targetPoints, t);
59 
60  t = t.inverse();
61  if (doScaleCheckBox_->isChecked()) {
62  BBox sbbox = computeBoundingBox(getPoints(sourceObject));
63  BBox tbbox = computeBoundingBox(targetPoints);
64  t = t * Scaling((tbbox.second - tbbox.first).cwiseQuotient(sbbox.second - sbbox.first));
65  }
66  transformObject(sourceObject, t);
67 
68  emit updatedObject(sourceId_, UPDATE_GEOMETRY);
69  emit createBackup(sourceId_, "Align", UPDATE_GEOMETRY);
70 }
71 
72 AlignPlugin::Point_container AlignPlugin::getPoints(BaseObjectData *object)
73 {
74  using namespace Eigen;
75 
76  Point_container points;
77 
78  if (object->dataType(DATA_HEXAHEDRAL_MESH)) {
80  for (OpenVolumeMesh::VertexIter it = mesh->vertices_begin(); it != mesh->vertices_end(); ++it) {
81  if (mesh->is_boundary(*it)) {
82  Vector3d p = Map<const Vector3d>(mesh->vertex(*it).data());
83  points.push_back(p);
84  }
85  }
86  } else if (object->dataType(DATA_POLYHEDRAL_MESH)) {
88  for (OpenVolumeMesh::VertexIter it = mesh->vertices_begin(); it != mesh->vertices_end(); ++it) {
89  if (mesh->is_boundary(*it)) {
90  Vector3d p = Map<const Vector3d>(mesh->vertex(*it).data());
91  points.push_back(p);
92  }
93  }
94  } else { // DATA_TRIANGLE_MESH
95  TriMesh *mesh = PluginFunctions::triMesh(object);
96  points.reserve(mesh->n_vertices());
97  for (TriMesh::VertexIter it = mesh->vertices_begin(); it != mesh->vertices_end(); ++it) {
98  Vector3d p = Map<const Vector3d>(mesh->point(*it).data());
99  points.push_back(p);
100  }
101  }
102 
103  return points;
104 }
105 
106 void AlignPlugin::transformObject(BaseObjectData *object, Eigen::Affine3d const& t)
107 {
108  using namespace Eigen;
109 
110  if (object->dataType(DATA_HEXAHEDRAL_MESH)) {
112  for (OpenVolumeMesh::VertexIter it = mesh->vertices_begin(); it != mesh->vertices_end(); ++it) {
113  ACG::Vec3d const& p = mesh->vertex(*it);
114  Vector3d ep(p[0], p[1], p[2]);
115  Vector3d tep = t * ep;
116  mesh->set_vertex(*it, ACG::Vec3d(tep[0], tep[1], tep[2]));
117  }
118  } else if (object->dataType(DATA_POLYHEDRAL_MESH)) {
120  for (OpenVolumeMesh::VertexIter it = mesh->vertices_begin(); it != mesh->vertices_end(); ++it) {
121  ACG::Vec3d const& p = mesh->vertex(*it);
122  Vector3d ep(p[0], p[1], p[2]);
123  Vector3d tep = t * ep;
124  mesh->set_vertex(*it, ACG::Vec3d(tep[0], tep[1], tep[2]));
125  }
126  } else { // DATA_TRIANGLE_MESH
127  TriMesh *mesh = PluginFunctions::triMesh(object);
128  for (TriMesh::VertexIter it = mesh->vertices_begin(); it != mesh->vertices_end(); ++it) {
129  ACG::Vec3d const& p = mesh->point(*it);
130  Vector3d ep(p[0], p[1], p[2]);
131  Vector3d tep = t * ep;
132  mesh->set_point(*it, ACG::Vec3d(tep[0], tep[1], tep[2]));
133  }
134  mesh->update_normals();
135  }
136 }
137 
138 void AlignPlugin::transformPoints(Point_container& points, Eigen::Affine3d const& t)
139 {
140  for (unsigned int i = 0; i < points.size(); ++i) {
141  points[i] = t * points[i];
142  }
143 }
144 
145 AlignPlugin::BBox AlignPlugin::computeBoundingBox(Point_container const& points)
146 {
147  using namespace Eigen;
148 
149  double inf = std::numeric_limits<double>::infinity();
150  Vector3d minp = Vector3d::Constant(inf);
151  Vector3d maxp = Vector3d::Constant(-inf);
152  for (unsigned int i = 0; i < points.size(); ++i) {
153  minp = minp.cwiseMin(points[i]);
154  maxp = maxp.cwiseMax(points[i]);
155  }
156 
157  return BBox(minp, maxp);
158 }
159 
160 Eigen::Vector3d AlignPlugin::computeCentroid(Point_container const& points)
161 {
162  using namespace Eigen;
163 
164  Vector3d centroid = Vector3d::Zero();
165  for (unsigned int i = 0; i < points.size(); ++i) {
166  centroid += points[i];
167  }
168  if (points.size() > 0) {
169  centroid /= points.size();
170  }
171  return centroid;
172 }
173 
174 bool AlignPlugin::computePCA(Point_container const& points, Eigen::Vector3d& centroid, Eigen::Matrix3d& principal_directions)
175 {
176  using namespace Eigen;
177 
178  centroid = computeCentroid(points);
179 
180  Matrix3d cov = Matrix3d::Zero();
181  for (unsigned int i = 0; i < points.size(); ++i) {
182  cov.noalias() += (points[i] - centroid) * (points[i] - centroid).transpose();
183  }
184  cov /= points.size() - 1;
185 
186  SelfAdjointEigenSolver<Matrix3d> eigensolver(cov);
187  principal_directions = eigensolver.eigenvectors();
188 
189  return eigensolver.info() == Success;
190 }
191 
192 #if QT_VERSION < 0x050000
193 Q_EXPORT_PLUGIN2(alignplugin, AlignPlugin)
194 #endif
PolyhedralMesh * polyhedralMesh(BaseObjectData *_object)
Get an PolyhedralMesh from an object.
bool dataType(DataType _type) const
Definition: BaseObject.cc:232
#define DATA_POLYHEDRAL_MESH
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
bool getObject(int _identifier, BSplineCurveObject *&_object)
HexahedralMesh * hexahedralMesh(BaseObjectData *_object)
Get an HexahedralMesh from an object.
const VecT & vertex(const VertexHandle &_vh) const
Get point _vh's coordinates.
void set_vertex(const VertexHandle &_vh, const VecT &_p)
Set the coordinates of point _vh.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
#define DATA_HEXAHEDRAL_MESH