CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxMesh.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 
13 #include "cxMesh.h"
14 #include <vtkCellArray.h>
15 #include <vtkColorSeries.h>
16 #include <vtkPolyData.h>
17 #include <vtkPointData.h>
18 #include <QDomDocument>
19 #include <QColor>
20 #include <QDir>
21 #include <vtkTransformTextureCoords.h>
22 #include <vtkTexture.h>
23 #include <vtkTextureMapToCylinder.h>
24 #include <vtkTextureMapToPlane.h>
25 #include <vtkTextureMapToSphere.h>
26 #include "cxTypeConversions.h"
28 #include "cxBoundingBox3D.h"
29 #include "vtkProperty.h"
30 #include "vtkImageData.h"
31 #include "cxImage.h"
32 #include "cxFileManagerService.h"
33 #include "cxLogger.h"
34 #include "cxNullDeleter.h"
35 
36 namespace cx
37 {
38 
39 
40 //---------------------------------------------------------
41 //---------------------------------------------------------
42 //---------------------------------------------------------
43 
44 MeshPtr Mesh::create(const QString& uid, const QString& name, PatientModelServicePtr patientModelService, SpaceProviderPtr spaceProvider)
45 {
46  return MeshPtr(new Mesh(uid, name, vtkPolyDataPtr(), patientModelService, spaceProvider));
47 }
48 
49 Mesh::Mesh(const QString& uid, const QString& name, vtkPolyDataPtr polyData, PatientModelServicePtr patientModelService, SpaceProviderPtr spaceProvider) :
50  Data(uid, name), mVtkPolyData(polyData), mHasGlyph(false), mOrientationArray(""), mColorArray(""), mPatientModelService(patientModelService),
51  mSpaceProvider(spaceProvider), mTextureData(patientModelService)
52 {
53  if (!mVtkPolyData)
54  mVtkPolyData = vtkPolyDataPtr::New();
55  connect(&mProperties, &MeshPropertyData::changed, this, &Mesh::meshChanged);
56  connect(&mTextureData, &MeshTextureData::changed, this, &Mesh::meshChanged);
57  mShowGlyph = shouldGlyphBeEnableByDefault();
58  mGlyphLUT ="Citrus";
59  this->setAcquisitionTime(QDateTime::currentDateTime());
60 }
61 
63 {
64 }
65 
66 void Mesh::setIsWireframe(bool on)
67 {
68  if (on)
69  mProperties.mRepresentation->setValue(QString::number(VTK_WIREFRAME));
70  else
71  mProperties.mRepresentation->setValue(QString::number(VTK_SURFACE));
72 }
73 
75 {
76  return mProperties.mRepresentation->getValue().toInt() == VTK_WIREFRAME;
77 }
78 
79 bool Mesh::load(QString path, FileManagerServicePtr filemanager)
80 {
81  vtkPolyDataPtr raw;
82  raw = filemanager->loadVtkPolyData(path);
83  if(raw)
84  {
85  this->setVtkPolyData(raw);
86  this->setName(QFileInfo(path).baseName());
87  this->setFilename(path); // need path even when not set explicitly: nice for testing
88  }
89  return raw!=0;
90 }
91 
92 void Mesh::setVtkPolyData(const vtkPolyDataPtr& polyData)
93 {
94  mVtkPolyData = polyData;
95  mVtkPolyDataOriginal = mVtkPolyData;
96  mOrientationArrayList.clear();
97  mColorArrayList.clear();
98 
99  if (mVtkPolyData)
100  {
101  int num;
102  for(int k=0; k < mVtkPolyData->GetPointData()->GetNumberOfArrays(); k++)
103  {
104  num=mVtkPolyData->GetPointData()->GetArray(k)->GetNumberOfComponents();
105  if(num==3)
106  {
107  if(strlen(mOrientationArray.c_str())==0)
108  {
109  mOrientationArray=mVtkPolyData->GetPointData()->GetArrayName(k);
110  mHasGlyph=true;
111  }
112  mOrientationArrayList << mVtkPolyData->GetPointData()->GetArrayName(k);
113  }
114  }
115  mColorArrayList << "";
116  mColorArray="";
117  for(int k=0; k < mVtkPolyData->GetPointData()->GetNumberOfArrays(); k++)
118  {
119  num=mVtkPolyData->GetPointData()->GetArray(k)->GetNumberOfComponents();
120  if(num==1)
121  {
122  mColorArrayList << mVtkPolyData->GetPointData()->GetArrayName(k);
123  }
124  }
125  }
126  mShowGlyph = shouldGlyphBeEnableByDefault();
127 
128  emit meshChanged();
129 }
131 {
132  return mVtkPolyData;
133 }
134 
136 {
137  return mVtkTexture;
138 }
139 
140 void Mesh::addXml(QDomNode& dataNode)
141 {
142  Data::addXml(dataNode);
143  QDomDocument doc = dataNode.ownerDocument();
144 
145  QDomNode meshNode = dataNode;
146 
147  mProperties.addXml(dataNode);
148  mTextureData.addXml(dataNode);
149 
150  QDomElement glyphNode = doc.createElement("glyph");
151  QDomElement elemGlyph = glyphNode.toElement();
152  elemGlyph.setAttribute("showGlyph", mShowGlyph);
153  elemGlyph.setAttribute("orientationArray", mOrientationArray.c_str());
154  elemGlyph.setAttribute("colorArray", mColorArray.c_str());
155  elemGlyph.setAttribute("glyphLUT", mGlyphLUT.c_str());
156  meshNode.appendChild(elemGlyph);
157 
158 }
159 
160 void Mesh::parseXml(QDomNode& dataNode)
161 {
162  Data::parseXml(dataNode);
163 
164  // image node must be parsed in the data manager to create this Image object
165  // Only subnodes are parsed here
166 
167  if (dataNode.isNull())
168  return;
169 
170  mProperties.parseXml(dataNode);
171  mTextureData.parseXml(dataNode);
172 
173  QDomNode glyphNode = dataNode.namedItem("glyph");
174  if (!glyphNode.isNull())
175  {
176  mShowGlyph = glyphNode.toElement().attribute("showGlyph").toInt();
177  mOrientationArray = glyphNode.toElement().attribute("orientationArray").toStdString();
178  mColorArray = glyphNode.toElement().attribute("colorArray").toStdString();
179  mGlyphLUT = glyphNode.toElement().attribute("glyphLUT").toStdString();
180  }
181 
182  emit meshChanged();
183 }
184 
185 void Mesh::setColor(const QColor& color)
186 {
187  mProperties.mColor->setValue(color);
188 }
189 
191 {
192  return mProperties.mColor->getValue();
193 }
194 
196 {
197  mProperties.mUseColorFromPolydataScalars->setValue(on);
198 }
199 
201 {
202  return mProperties.mUseColorFromPolydataScalars->getValue();
203 }
204 
205 void Mesh::setBackfaceCullingSlot(bool backfaceCulling)
206 {
207  mProperties.mBackfaceCulling->setValue(backfaceCulling);
208 }
209 
211 {
212  return mProperties.mBackfaceCulling->getValue();
213 }
214 
215 void Mesh::setFrontfaceCullingSlot(bool frontfaceCulling)
216 {
217  mProperties.mFrontfaceCulling->setValue(frontfaceCulling);
218  emit meshChanged();
219 }
220 
222 {
223  return mProperties.mFrontfaceCulling->getValue();
224 }
225 
226 void Mesh::setShowGlyph(bool val)
227 {
228  mShowGlyph = val;
229  emit meshChanged();
230 }
231 
233 {
234  return mHasGlyph;
235 }
236 
238 {
239  return mShowGlyph;
240 }
241 
242 bool Mesh::shouldGlyphBeEnableByDefault()
243 {
244  if(! mHasGlyph) return false;
245  if(!mVtkPolyData) return false;
246  if(mVtkPolyData->GetNumberOfVerts() > 0) return false;
247  if(mVtkPolyData->GetNumberOfLines() > 0) return false;
248  if(mVtkPolyData->GetNumberOfPolys() > 0) return false;
249  if(mVtkPolyData->GetNumberOfStrips() > 0) return false;
250 
251  return true;
252 }
253 
254 
256 {
257  return mOrientationArray.c_str();
258 }
259 
260 void Mesh::setOrientationArray(const char * orientationArray)
261 {
262  mOrientationArray = orientationArray;
263  emit meshChanged();
264 }
265 
267 {
268  return mProperties.mVisSize->getValue();
269 }
270 
271 void Mesh::setVisSize(double size)
272 {
273  mProperties.mVisSize->setValue(size);
274 }
275 
276 const char * Mesh::getColorArray()
277 {
278  return mColorArray.c_str();
279 }
280 
281 void Mesh::setColorArray(const char * colorArray)
282 {
283  mColorArray = colorArray;
284  emit meshChanged();
285 }
286 
287 const char * Mesh::getGlyphLUT()
288 {
289  return mGlyphLUT.c_str();
290 }
291 
293 {
294  return mTextureData.getTextureShape()->getValue();
295 }
296 
297 void Mesh::setGlyphLUT(const char * glyphLUT)
298 {
299  mGlyphLUT = glyphLUT;
300  emit meshChanged();
301 }
302 
303 bool Mesh::hasTexture() const
304 {
305  if(mTextureData.getTextureImage()->getValue().isEmpty() || mTextureData.getTextureImage()->getImage() == NULL)
306  return false;
307  else
308  return true;
309 }
310 
312 {
313  if (!this->hasTexture())
314  {
315  mVtkTexture = NULL;
316  if(mVtkPolyDataOriginal)
317  mVtkPolyData = mVtkPolyDataOriginal;
318  return;
319  }
320 
321  //create the texture mapper
322  vtkDataSetAlgorithmPtr tMapper;
323  if(!this->createTextureMapper(tMapper))
324  return;
325 
326  //Get the image data
327  ImagePtr textureImage = mTextureData.getTextureImage()->getImage();
328  vtkImageDataPtr vtkImageData = textureImage->getBaseVtkImageData();
329 
330  //Create the texture
331  mVtkTexture = vtkTexturePtr::New();
332  mVtkTexture->SetRepeat(mTextureData.getRepeat()->getValue());
333  mVtkTexture->SetInputData(vtkImageData);
334 
335  //transform texture coordinates
336  //VTK uses r, s and t coordinates. t is only used for 3D texturing which is not supported by VTK yet.
337  //We map r and s to match the CustusX X and Y directions.
338  vtkTransformTextureCoordsPtr transformTexture = vtkTransformTextureCoordsPtr::New();
339  transformTexture->SetInputConnection(tMapper->GetOutputPort());
340  double posR = this->getTextureData().getPositionX()->getValue();
341  double posS = this->getTextureData().getPositionY()->getValue();
342  transformTexture->SetPosition(-posR, -posS, 0);
343  double scaleR = this->getTextureData().getScaleX()->getValue();
344  double scaleS = this->getTextureData().getScaleY()->getValue();
345  transformTexture->SetScale(scaleR, scaleS, 1);
346  transformTexture->Update();
347 
348  //Update the poly data
349  mVtkPolyData = transformTexture->GetPolyDataOutput();
350 }
351 
352 bool Mesh::createTextureMapper(vtkDataSetAlgorithmPtr &tMapper)
353 {
354  QString textureShape = this->getTextureShape();
355 
356  if (textureShape == mTextureData.getCylinderText())
357  {
358  tMapper = vtkTextureMapToCylinderPtr::New();
359  dynamic_cast<vtkTextureMapToCylinder*>(tMapper.Get())->PreventSeamOn();
360  }
361  else if (textureShape == mTextureData.getPlaneText())
362  {
363  vtkTextureMapToPlanePtr mapper = vtkTextureMapToPlanePtr::New();
364  DoubleBoundingBox3D bb = this->boundingBox();
365  // Explicitly state the plane as the upper xy-plane of the bounding box
366  // The automatic plane generation is not deterministic for square cases.
367  mapper->SetOrigin(bb.corner(0,0,1).data());
368  mapper->SetPoint1(bb.corner(1,0,1).data());
369  mapper->SetPoint2(bb.corner(0,1,1).data());
370 
371  tMapper = mapper;
372  }
373  else if (textureShape == mTextureData.getSphereText())
374  {
375  tMapper = vtkTextureMapToSpherePtr::New();
376  }
377  else
378  {
379  return false;
380  }
381 
382  tMapper->SetInputData(mVtkPolyData);
383  return true;
384 }
385 
387 {
388  return mOrientationArrayList;
389 }
390 
392 {
393  return mColorArrayList;
394 }
395 
397 {
398  return mProperties;
399 }
400 
402 {
403  return mTextureData;
404 }
405 
407 {
408  // getVtkPolyData()->Update();
409  DoubleBoundingBox3D bounds(getVtkPolyData()->GetBounds());
410  return bounds;
411 }
412 
414 {
415  // if transform elements exists, create a copy with entire position inside the polydata:
416  if (similar(transform, Transform3D::Identity()))
417  {
418  vtkPolyDataPtr poly = vtkPolyDataPtr::New();
419  poly->DeepCopy(getVtkPolyData());
420  return poly;
421  }
422 
423  vtkPolyDataPtr poly = vtkPolyDataPtr::New();
424  poly->DeepCopy(getVtkPolyData());
425  vtkPointsPtr points = poly->GetPoints();
426 
427  vtkPointsPtr floatPoints = vtkPointsPtr::New();
428  floatPoints->DeepCopy(points);
429  floatPoints->SetDataTypeToFloat();
430  for (int i = 0; i < poly->GetNumberOfPoints(); ++i)
431  {
432  Vector3D p(points->GetPoint(i));
433  p = transform.coord(p);
434  floatPoints->SetPoint(i, p.begin());
435  }
436  poly->SetPoints(floatPoints.GetPointer());
437  poly->Modified();
438 
439  return poly;
440 }
441 
443 {
445  return poly->GetLines()->GetNumberOfCells() > 0 && poly->GetPolys()->GetNumberOfCells() == 0 && poly->GetStrips()->GetNumberOfCells() == 0;
446 }
447 
448 void Mesh::save(const QString& basePath, FileManagerServicePtr fileManager)
449 {
450  QString filename = basePath + "/Images/" + this->getUid() + ".vtk";
451  this->setFilename(QDir(basePath).relativeFilePath(filename));
452  MeshPtr self = MeshPtr(this, null_deleter());
453  fileManager->save(self, filename);
454 
455 }
456 
457 } // namespace cx
virtual DoubleBoundingBox3D boundingBox() const
Definition: cxMesh.cpp:406
boost::shared_ptr< class SpaceProvider > SpaceProviderPtr
bool hasGlyph()
Definition: cxMesh.cpp:232
vtkSmartPointer< class vtkTexture > vtkTexturePtr
BoolPropertyBasePtr mUseColorFromPolydataScalars
boost::shared_ptr< class FileManagerService > FileManagerServicePtr
virtual bool load(QString path, FileManagerServicePtr filemanager)
Definition: cxMesh.cpp:79
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
Vector3D corner(int x, int y, int z) const
DoublePropertyPtr mVisSize
const char * getOrientationArray()
Definition: cxMesh.cpp:255
Mesh(const QString &uid, const QString &name="", vtkPolyDataPtr polyData=vtkPolyDataPtr(), PatientModelServicePtr patientModelService=PatientModelService::getNullObject(), SpaceProviderPtr spaceProvider=SpaceProvider::getNullObject())
Definition: cxMesh.cpp:49
bool isFiberBundle() const
Definition: cxMesh.cpp:442
void parseXml(QDomNode dataNode)
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
vtkSmartPointer< class vtkDataSetAlgorithm > vtkDataSetAlgorithmPtr
void parseXml(QDomNode &dataNode)
BoolPropertyPtr mFrontfaceCulling
void setVisSize(double size)
Definition: cxMesh.cpp:271
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
void setName(const QString &name)
Definition: cxData.cpp:58
virtual vtkPolyDataPtr getVtkPolyData() const
Definition: cxMesh.cpp:130
vtkSmartPointer< vtkPoints > vtkPointsPtr
void updateVtkPolyDataWithTexture()
Definition: cxMesh.cpp:311
void setFrontfaceCullingSlot(bool backfaceCulling)
Set frontface culling on/off in mesh visualization.
Definition: cxMesh.cpp:215
QStringList getColorArrayList()
Definition: cxMesh.cpp:391
virtual void addXml(QDomNode &dataNode)
adds xml information about the data and its variabels
Definition: cxData.cpp:123
vtkSmartPointer< class vtkTransformTextureCoords > vtkTransformTextureCoordsPtr
vtkSmartPointer< class vtkTextureMapToPlane > vtkTextureMapToPlanePtr
QString getTextureShape()
Definition: cxMesh.cpp:292
DoublePropertyPtr getPositionY() const
QString getPlaneText() const
virtual QString getUid() const
Definition: cxData.cpp:64
DoublePropertyPtr getScaleX() const
bool hasTexture() const
Definition: cxMesh.cpp:303
StringPropertySelectImagePtr getTextureImage() const
bool getIsWireframe() const
true=wireframe, false=surface
Definition: cxMesh.cpp:74
DoublePropertyPtr getPositionX() const
StringPropertyPtr mRepresentation
static MeshPtr create(const QString &uid, const QString &name="", PatientModelServicePtr patientModelService=PatientModelService::getNullObject(), SpaceProviderPtr spaceProvider=SpaceProvider::getNullObject())
Definition: cxMesh.cpp:44
QString getSphereText() const
bool showGlyph()
Definition: cxMesh.cpp:237
void setBackfaceCullingSlot(bool backfaceCulling)
Set backface culling on/off in mesh visualization.
Definition: cxMesh.cpp:205
BoolPropertyPtr getRepeat() const
void setVtkPolyData(const vtkPolyDataPtr &polyData)
Definition: cxMesh.cpp:92
virtual void parseXml(QDomNode &dataNode)
Use a XML node to load data.
Definition: cxData.cpp:149
bool getBackfaceCulling()
Get backface culling.
Definition: cxMesh.cpp:210
virtual void save(const QString &basePath, FileManagerServicePtr fileManager)
Definition: cxMesh.cpp:448
void setOrientationArray(const char *orientationArray)
Definition: cxMesh.cpp:260
boost::shared_ptr< class PatientModelService > PatientModelServicePtr
void setAcquisitionTime(QDateTime time)
Definition: cxData.cpp:194
void meshChanged()
BoolPropertyPtr mBackfaceCulling
void addXml(QDomNode &dataNode)
Representation of a floating-point bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
void setIsWireframe(bool on)
Set rep to wireframe, false means surface.
Definition: cxMesh.cpp:66
void setUseColorFromPolydataScalars(bool on)
Definition: cxMesh.cpp:195
void setGlyphLUT(const char *glyphLUT)
Definition: cxMesh.cpp:297
const MeshTextureData & getTextureData() const
Definition: cxMesh.cpp:401
const char * getGlyphLUT()
Definition: cxMesh.cpp:287
vtkSmartPointer< vtkPolyData > vtkPolyDataPtr
virtual void parseXml(QDomNode &dataNode)
Use a XML node to load data.
Definition: cxMesh.cpp:160
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:42
DoublePropertyPtr getScaleY() const
Superclass for all data objects.
Definition: cxData.h:89
QString getCylinderText() const
void addXml(QDomNode &dataNode)
adds xml information about the image and its variabels
Definition: cxMesh.cpp:140
virtual ~Mesh()
Definition: cxMesh.cpp:62
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
void addXml(QDomNode &dataNode)
void setShowGlyph(bool val)
Definition: cxMesh.cpp:226
vtkPolyDataPtr getTransformedPolyDataCopy(Transform3D tranform)
Create a new transformed polydata.
Definition: cxMesh.cpp:413
bool getFrontfaceCulling()
Get frontface culling.
Definition: cxMesh.cpp:221
const MeshPropertyData & getProperties() const
Definition: cxMesh.cpp:396
void setColorArray(const char *colorArray)
Definition: cxMesh.cpp:281
boost::shared_ptr< class Mesh > MeshPtr
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
QStringList getOrientationArrayList()
Definition: cxMesh.cpp:386
virtual vtkTexturePtr getVtkTexture() const
Definition: cxMesh.cpp:135
double getVisSize()
Definition: cxMesh.cpp:266
StringPropertyPtr getTextureShape() const
const char * getColorArray()
Definition: cxMesh.cpp:276
virtual void setFilename(QString val)
Definition: cxData.cpp:78
bool getUseColorFromPolydataScalars() const
Definition: cxMesh.cpp:200
ColorPropertyPtr mColor
void setColor(const QColor &color)
Set the color of the mesh.
Definition: cxMesh.cpp:185
QColor getColor()
Get the color of the mesh (Values are range 0 - 255)
Definition: cxMesh.cpp:190
Namespace for all CustusX production code.