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