1 // Copyright (C) 2017-2019 EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (EDF R&D)
21 #include "vtkDevelopedSurface.h"
22 #include "VTKToMEDMem.hxx"
24 #include "vtkAdjacentVertexIterator.h"
25 #include "vtkIntArray.h"
26 #include "vtkCellData.h"
27 #include "vtkPointData.h"
28 #include "vtkCylinder.h"
30 #include "vtkCutter.h"
31 #include "vtkTransform.h"
33 #include "vtkStreamingDemandDrivenPipeline.h"
34 #include "vtkUnstructuredGrid.h"
35 #include "vtkMultiBlockDataSet.h"
37 #include "vtkInformationStringKey.h"
38 #include "vtkAlgorithmOutput.h"
39 #include "vtkObjectFactory.h"
40 #include "vtkMutableDirectedGraph.h"
41 #include "vtkMultiBlockDataSet.h"
42 #include "vtkDataSet.h"
43 #include "vtkInformationVector.h"
44 #include "vtkInformation.h"
45 #include "vtkDataArraySelection.h"
46 #include "vtkTimeStamp.h"
47 #include "vtkInEdgeIterator.h"
48 #include "vtkInformationDataObjectKey.h"
49 #include "vtkExecutive.h"
50 #include "vtkVariantArray.h"
51 #include "vtkStringArray.h"
52 #include "vtkDoubleArray.h"
53 #include "vtkFloatArray.h"
54 #include "vtkCharArray.h"
55 #include "vtkUnsignedCharArray.h"
56 #include "vtkDataSetAttributes.h"
57 #include "vtkDemandDrivenPipeline.h"
58 #include "vtkDataObjectTreeIterator.h"
59 #include "vtkWarpScalar.h"
61 #include "MEDCouplingMemArray.hxx"
63 #include "VTKMEDTraits.hxx"
66 #define _USE_MATH_DEFINES
75 vtkStandardNewMacro(vtkDevelopedSurface);
85 struct VTKTraits<double>
87 typedef vtkDoubleArray ArrayType;
91 struct VTKTraits<float>
93 typedef vtkFloatArray ArrayType;
96 void ExtractInfo(vtkInformationVector *inputVector, vtkDataSet *& usgIn)
98 vtkInformation *inputInfo(inputVector->GetInformationObject(0));
100 vtkDataSet *input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT())));
101 vtkMultiBlockDataSet *input1(vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT())));
107 throw MZCException("Input dataSet must be a DataSet or single elt multi block dataset expected !");
108 if(input1->GetNumberOfBlocks()!=1)
109 throw MZCException("Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or ExtractBlocks filter before calling this filter !");
110 vtkDataObject *input2(input1->GetBlock(0));
112 throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is NULL !");
113 vtkDataSet *input2c(vtkDataSet::SafeDownCast(input2));
115 throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !");
119 throw MZCException("Input data set is NULL !");
120 vtkPointData *att(input->GetPointData());
122 throw MZCException("Input dataset has no point data attribute ! Impossible to deduce a developed surface on it !");
126 class vtkDevelopedSurface::vtkInternals
129 vtkNew<vtkCutter> Cutter;
134 vtkDevelopedSurface::vtkDevelopedSurface():_cyl(nullptr),Internal(new vtkInternals),InvertStatus(false),OffsetInRad(0.)
136 //this->RegisterFilter(this->Internal->Cutter.GetPointer());
139 vtkDevelopedSurface::~vtkDevelopedSurface()
141 delete this->Internal;
144 void vtkDevelopedSurface::SetInvertWay(bool invertStatus)
146 this->InvertStatus=invertStatus;
150 void vtkDevelopedSurface::SetThetaOffset(double offsetInDegrees)
152 double tmp(std::min(offsetInDegrees,180.));
153 tmp=std::max(tmp,-180.);
154 this->OffsetInRad=tmp/180.*M_PI;
158 int vtkDevelopedSurface::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector)
160 //std::cerr << "########################################## vtkDevelopedSurface::RequestInformation ##########################################" << std::endl;
163 vtkDataSet *usgIn(0);
164 ExtractInfo(inputVector[0],usgIn);
166 catch(MZCException& e)
168 std::ostringstream oss;
169 oss << "Exception has been thrown in vtkDevelopedSurface::RequestInformation : " << e.what() << std::endl;
170 if(this->HasObserver("ErrorEvent") )
171 this->InvokeEvent("ErrorEvent",const_cast<char *>(oss.str().c_str()));
173 vtkOutputWindowDisplayErrorText(const_cast<char *>(oss.str().c_str()));
174 vtkObject::BreakOnError();
180 std::vector<int> UnWrapByDuplicatingNodes(vtkCellArray *ca, vtkIdType& offset, const MEDCoupling::DataArrayDouble *thetas)
182 std::vector<int> ret;
183 vtkIdType nbCells(ca->GetNumberOfCells());
184 vtkIdType *conn(ca->GetPointer());
185 const double *tptr(thetas->begin());
186 for(vtkIdType i=0;i<nbCells;i++)
188 vtkIdType sz(*conn++);
189 double ma(-std::numeric_limits<double>::max()),mi(std::numeric_limits<double>::max());
190 for(vtkIdType j=0;j<sz;j++)
192 double tmp_theta(tptr[conn[j]]);
193 ma=std::max(ma,tmp_theta);
194 mi=std::min(mi,tmp_theta);
198 for(vtkIdType j=0;j<sz;j++)
200 double tmp_theta(tptr[conn[j]]);
203 ret.push_back(conn[j]);
214 void DealArray(vtkDataSetAttributes *pd, int pos, typename MEDFileVTKTraits<T>::VtkType *arr, std::vector<int>& nodeSel)
216 int nbc(arr->GetNumberOfComponents());
217 std::size_t nbt(nodeSel.size());
218 vtkSmartPointer< typename MEDFileVTKTraits<T>::VtkType > newArr;
219 newArr.TakeReference(MEDFileVTKTraits<T>::VtkType::New());
220 newArr->SetNumberOfComponents(nbc);
221 newArr->SetNumberOfTuples(nbt);
222 T *ptr(newArr->GetPointer(0));
223 const T *inPtr(arr->GetPointer(0));
224 for(std::size_t i=0;i<nbt;i++)
226 ptr=std::copy(inPtr+nbc*nodeSel[i],inPtr+nbc*(nodeSel[i]+1),ptr);
228 newArr->SetName(arr->GetName());
229 arr->DeepCopy(newArr);
232 void ToDouble(vtkDataArray *coords, vtkSmartPointer<vtkDoubleArray>& coordsOut)
234 vtkDoubleArray *coords2(vtkDoubleArray::SafeDownCast(coords));
235 vtkFloatArray *coords3(vtkFloatArray::SafeDownCast(coords));
236 if(!coords2 && !coords3)
237 throw MZCException("Input coordinates are neither float64 or float32 !");
241 coordsOut.TakeReference(coords2);
242 coords2->Register(0);
246 coordsOut.TakeReference(vtkDoubleArray::New());
247 coordsOut->SetNumberOfComponents(3);
248 vtkIdType nbTuples(coords3->GetNumberOfTuples());
249 coordsOut->SetNumberOfTuples(nbTuples);
250 std::copy(coords3->GetPointer(0),coords3->GetPointer(0)+3*nbTuples,coordsOut->GetPointer(0));
254 void dealWith(vtkPolyData *outdata, const double center[3], const double axis[3], double radius, double eps, bool invertThetaInc, double offsetInRad)
256 vtkDataArray *coords(outdata->GetPoints()->GetData());
257 if(coords->GetNumberOfComponents()!=3)
258 throw MZCException("Input coordinates are expected to have 3 components !");
260 vtkIdType nbNodes(coords->GetNumberOfTuples());
262 throw MZCException("No points -> impossible to develop anything !");
264 vtkSmartPointer<vtkDoubleArray> zeCoords;
265 ToDouble(coords,zeCoords);
267 double axis_cross_Z[3]={axis[1],-axis[0],0.};
268 double n_axis(sqrt(axis_cross_Z[0]*axis_cross_Z[0]+axis_cross_Z[1]*axis_cross_Z[1]));
271 double ang(asin(n_axis));
274 MEDCoupling::DataArrayDouble::Rotate3DAlg(center,axis_cross_Z,ang,nbNodes,zeCoords->GetPointer(0),zeCoords->GetPointer(0));
277 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> c_cyl;
279 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> cc(MEDCoupling::DataArrayDouble::New()); cc->alloc(nbNodes,3);
280 double *ccPtr(cc->getPointer());
281 const double *zeCoordsPtr(zeCoords->GetPointer(0));
282 for(vtkIdType i=0;i<nbNodes;i++,ccPtr+=3,zeCoordsPtr+=3)
284 std::transform(zeCoordsPtr,zeCoordsPtr+3,center,ccPtr,std::minus<double>());
286 c_cyl=cc->fromCartToCyl();
288 MEDCoupling::MCAuto<MEDCoupling::MEDFileData> mfd(MEDCoupling::MEDFileData::New());
289 WriteMEDFileFromVTKDataSet(mfd,outdata,{},0.,0);
292 MEDCoupling::MEDFileMeshes *ms(mfd->getMeshes());
293 if(ms->getNumberOfMeshes()!=1)
294 throw MZCException("Unexpected number of meshes !");
295 MEDCoupling::MEDFileMesh *mm(ms->getMeshAtPos(0));
296 MEDCoupling::MEDFileUMesh *mmu(dynamic_cast<MEDCoupling::MEDFileUMesh *>(mm));
298 throw MZCException("Expecting unstructured one !");
299 MEDCoupling::MCAuto<MEDCoupling::MEDCouplingUMesh> m0(mmu->getMeshAtLevel(0));
302 MEDCoupling::MCAuto<MEDCoupling::DataArrayInt> c0s(m0->getCellIdsLyingOnNodes(&v,&v+1,false));
304 throw MZCException("Orphan node 0 !");
305 std::vector<int> nodes0;
306 m0->getNodeIdsOfCell(c0s->getIJ(0,0),nodes0);
307 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> tmp0(c_cyl->selectByTupleIdSafe(nodes0.data(),nodes0.data()+nodes0.size()));
308 tmp0=tmp0->keepSelectedComponents({1});
309 double tmp(tmp0->getMaxAbsValueInArray());
314 constexpr double EPS_FOR_RADIUS=1e-2;
315 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> rs(c_cyl->keepSelectedComponents({0}));
316 if(!rs->isUniform(radius,radius*EPS_FOR_RADIUS))
318 double mi(rs->getMinValueInArray()),ma(rs->getMaxValueInArray());
319 std::ostringstream oss; oss << "Looks not really a cylinder within given precision ! Range is [" << mi << "," << ma << "] expecting " << radius << " within precision of " << radius*EPS_FOR_RADIUS << " !";
320 throw MZCException(oss.str());
322 double tetha0(c_cyl->getIJ(0,1));
324 double *ccylptr(c_cyl->getPointer()+1);
325 double mi02(std::numeric_limits<double>::max());
326 for(vtkIdType i=0;i<nbNodes;i++,ccylptr+=3)
328 *ccylptr-=tetha0+offsetInRad;
329 mi02=std::min(mi02,*ccylptr);
333 ccylptr=c_cyl->getPointer()+1;
334 for(vtkIdType i=0;i<nbNodes;i++,ccylptr+=3)
344 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> c_cyl_2(c_cyl->keepSelectedComponents({1}));
346 MEDCoupling::MCAuto<MEDCoupling::DataArrayInt> poses(c_cyl_2->findIdsInRange(0.,eps));
347 c_cyl->setPartOfValuesSimple3(0.,poses->begin(),poses->end(),1,2,1);
350 if(a ^ (!invertThetaInc))
352 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> tmp(c_cyl->keepSelectedComponents({1}));
354 std::for_each(tmp->getPointer(),tmp->getPointer()+tmp->getNumberOfTuples(),[](double& v) { if(v==-0.) v=0.; });
355 c_cyl->setPartOfValues1(tmp,0,nbNodes,1,1,2,1);
357 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> c_cyl_post(c_cyl->keepSelectedComponents({1}));
359 double *c_cyl_post_ptr(c_cyl_post->getPointer());
360 for(vtkIdType i=0;i<nbNodes;i++,c_cyl_post_ptr++)
362 if(*c_cyl_post_ptr<0.)
363 *c_cyl_post_ptr+=2*M_PI;
366 vtkCellArray *cb(outdata->GetPolys());
367 vtkIdType offset(nbNodes);
368 std::vector<int> dupNodes(UnWrapByDuplicatingNodes(cb,offset,c_cyl_post));
370 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> c_cyl_post2(c_cyl_post->selectByTupleId(dupNodes.data(),dupNodes.data()+dupNodes.size()));
371 c_cyl_post2->applyLin(1.,2*M_PI);
372 c_cyl_post=MEDCoupling::DataArrayDouble::Aggregate(c_cyl_post,c_cyl_post2);
373 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> z0(c_cyl->keepSelectedComponents({2}));
374 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> z1(z0->selectByTupleId(dupNodes.data(),dupNodes.data()+dupNodes.size()));
375 z0=MEDCoupling::DataArrayDouble::Aggregate(z0,z1);
377 std::size_t outNbNodes(z0->getNumberOfTuples());
378 vtkSmartPointer<vtkDoubleArray> zeCoords2;
379 zeCoords2.TakeReference(vtkDoubleArray::New());
380 zeCoords2->SetNumberOfComponents(3);
381 zeCoords2->SetNumberOfTuples(outNbNodes);
383 const double *tptr(c_cyl_post->begin()),*zptr(z0->begin());
384 double *outPtr(zeCoords2->GetPointer(0));
385 for(std::size_t i=0;i<outNbNodes;i++,tptr++,zptr++,outPtr+=3)
387 outPtr[0]=radius*(*tptr);
393 outdata->GetPoints()->SetData(zeCoords2);
394 // now post process nodes
395 std::vector<int> nodeSel(nbNodes+dupNodes.size());
398 std::for_each(nodeSel.begin(),nodeSel.begin()+nbNodes,[&cnt](int& v){ v=cnt++; });
399 std::copy(dupNodes.begin(),dupNodes.end(),nodeSel.begin()+nbNodes);
401 vtkDataSetAttributes *pd(outdata->GetPointData());
402 int nba(pd->GetNumberOfArrays());
403 for(int i=0;i<nba;i++)
405 vtkDataArray *arr(pd->GetArray(i));
407 vtkIntArray *arr0(vtkIntArray::SafeDownCast(arr));
410 DealArray<int>(pd,i,arr0,nodeSel);
415 vtkFloatArray *arr0(vtkFloatArray::SafeDownCast(arr));
418 DealArray<float>(pd,i,arr0,nodeSel);
423 vtkDoubleArray *arr0(vtkDoubleArray::SafeDownCast(arr));
426 DealArray<double>(pd,i,arr0,nodeSel);
433 int vtkDevelopedSurface::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector)
435 //std::cerr << "########################################## vtkDevelopedSurface::RequestData ##########################################" << std::endl;
439 throw MZCException("No cylinder object as cut function !");
440 double center[3],axis[3],radius;
441 vtkAbstractTransform* trf(_cyl->GetTransform());
443 _cyl->GetCenter(center);
444 _cyl->GetAxis(axis[0],axis[1],axis[2]);
445 radius=_cyl->GetRadius();
449 double axis3[3]={center[0]+0.,center[1]+1.,center[2]+0.},axis4[3];
450 trf->TransformPoint(axis3,axis4);
451 std::transform(axis4,axis4+3,center,axis,[](double a, double b) { return b-a; });
453 if(std::isnan(axis[0]) && std::isnan(axis[1]) && std::isnan(axis[2]))
454 { axis[0]=0.; axis[1]=-1.; axis[2]=0.; }
456 //std::cerr << trf << " jjj " << axis[0] << " " << axis[1] << " " << axis[2] << " : " << center[0] << " " << center[1] << " " << center[2] << " " " " << " -> " << radius << std::endl;
457 vtkDataSet *usgIn(0);
458 ExtractInfo(inputVector[0],usgIn);
459 vtkSmartPointer<vtkPolyData> outData;
461 vtkNew<vtkCutter> Cutter;
462 Cutter->SetInputData(usgIn);
463 Cutter->SetCutFunction(_cyl);
465 vtkDataSet *zeComputedOutput(Cutter->GetOutput());
466 vtkPolyData *zeComputedOutput2(vtkPolyData::SafeDownCast(zeComputedOutput));
467 if(!zeComputedOutput2)
468 throw MZCException("Unexpected output of cutter !");
469 outData.TakeReference(zeComputedOutput2);
470 zeComputedOutput2->Register(0);
472 if(outData->GetNumberOfCells()==0)
473 return 1;// no cells -> nothing to do
475 dealWith(outData,center,axis,radius,1e-7,this->InvertStatus,this->OffsetInRad);
477 vtkInformation *outInfo(outputVector->GetInformationObject(0));
478 vtkPolyData *output(vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())));
479 output->ShallowCopy(outData);
481 catch(MZCException& e)
483 std::ostringstream oss;
484 oss << "Exception has been thrown in vtkDevelopedSurface::RequestInformation : " << e.what() << std::endl;
485 if(this->HasObserver("ErrorEvent") )
486 this->InvokeEvent("ErrorEvent",const_cast<char *>(oss.str().c_str()));
488 vtkOutputWindowDisplayErrorText(const_cast<char *>(oss.str().c_str()));
489 vtkObject::BreakOnError();
495 int vtkDevelopedSurface::FillOutputPortInformation( int vtkNotUsed(port), vtkInformation* info)
497 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPolyData");
502 void vtkDevelopedSurface::PrintSelf(ostream& os, vtkIndent indent)
504 this->Superclass::PrintSelf(os, indent);
507 void vtkDevelopedSurface::SetCutFunction(vtkImplicitFunction* func)
509 vtkCylinder *cyl(vtkCylinder::SafeDownCast(func));
517 vtkMTimeType vtkDevelopedSurface::GetMTime()
519 vtkMTimeType maxMTime = this->Superclass::GetMTime(); // My MTime
522 maxMTime=std::max(maxMTime,_cyl->GetMTime());