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