Salome HOME
Copyright update 2020
[modules/smesh.git] / src / OBJECT / SMESH_FaceOrientationFilter.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SMESH_FaceOrientationFilter.h"
21 #include "SMESH_ActorUtils.h"
22
23 #include "SUIT_Session.h"
24 #include "SUIT_ResourceMgr.h"
25
26 #include <VTKViewer_CellCenters.h>
27
28 #include <vtkCellArray.h>
29 #include <vtkCellData.h>
30 #include <vtkDataSet.h>
31 #include <vtkFloatArray.h>
32 #include <vtkGlyph3D.h>
33 #include <vtkGlyphSource2D.h>
34 #include <vtkInformation.h>
35 #include <vtkInformationVector.h>
36 #include <vtkMaskPoints.h>
37 #include <vtkObjectFactory.h>
38 #include <vtkPolyData.h>
39 #include <vtkPolygon.h>
40
41 #include <QColor>
42
43 #define PI   3.14159265359
44
45 vtkStandardNewMacro(SMESH_FaceOrientationFilter);
46
47 /*!
48  * \class SMESH_FaceOrientationFilter
49  * Passive filter take a polydata as input and create a dataset as output.
50  */
51
52 SMESH_FaceOrientationFilter::SMESH_FaceOrientationFilter()
53 {
54   SUIT_ResourceMgr* mgr = SUIT_Session::session()->resourceMgr();
55   myOrientationScale = mgr->doubleValue( "SMESH", "orientation_scale", 0.1 );
56   my3dVectors = mgr->booleanValue( "SMESH", "orientation_3d_vectors", false );
57
58   myArrowPolyData = CreateArrowPolyData();
59
60   myFacePolyData = vtkPolyData::New();
61
62   myFaceCenters = VTKViewer_CellCenters::New();
63   myFaceCenters->SetInputData(myFacePolyData);
64
65   myFaceMaskPoints = vtkMaskPoints::New();
66   myFaceMaskPoints->SetInputConnection(myFaceCenters->GetOutputPort());
67   myFaceMaskPoints->SetOnRatio(1);
68
69   myGlyphSource = vtkGlyphSource2D::New();
70   myGlyphSource->SetGlyphTypeToThickArrow();
71   myGlyphSource->SetFilled(0);
72   myGlyphSource->SetCenter(0.5, 0.0, 0.0);
73
74   myBaseGlyph = vtkGlyph3D::New();
75   myBaseGlyph->SetInputConnection(myFaceMaskPoints->GetOutputPort());
76   myBaseGlyph->SetVectorModeToUseVector();
77   myBaseGlyph->SetScaleModeToDataScalingOff();
78   myBaseGlyph->SetColorModeToColorByScalar();
79   if( my3dVectors )
80     myBaseGlyph->SetSourceData(myArrowPolyData);
81   else
82     myBaseGlyph->SetSourceConnection(myGlyphSource->GetOutputPort());
83 }
84
85 SMESH_FaceOrientationFilter::~SMESH_FaceOrientationFilter()
86 {
87   myArrowPolyData->Delete();
88   myFacePolyData->Delete();
89   myFaceCenters->Delete();
90   myFaceMaskPoints->Delete();
91   myGlyphSource->Delete();
92   myBaseGlyph->Delete();
93 }
94
95 void SMESH_FaceOrientationFilter::SetOrientationScale( double theScale )
96 {
97   myOrientationScale = theScale;
98   Modified();
99 }
100
101 void SMESH_FaceOrientationFilter::Set3dVectors( bool theState )
102 {
103   my3dVectors = theState;
104   if( my3dVectors )
105     myBaseGlyph->SetSourceData(myArrowPolyData);
106   else
107     myBaseGlyph->SetSourceConnection(myGlyphSource->GetOutputPort());
108   Modified();
109 }
110
111 vtkPolyData* SMESH_FaceOrientationFilter::CreateArrowPolyData()
112 {
113   vtkPoints* points = vtkPoints::New();
114   vtkCellArray* polys = vtkCellArray::New();
115
116   float l1 = 0.8;
117   float l2 = 1.0;
118   int n = 16;
119   float r1 = 0.04;
120   float r2 = 0.08;
121   float angle = 2. * PI / n;
122   float p[3];
123   vtkIdType c3[3];
124   vtkIdType c4[4];
125
126   float p0[3] = { 0.0, 0.0, 0.0 };
127   float p1[3] = {  l1, 0.0, 0.0 };
128   float p2[3] = {  l2, 0.0, 0.0 };
129
130   points->InsertPoint( 0, p0 );
131   points->InsertPoint( 1, p1 );
132   points->InsertPoint( 2, p2 );
133
134   // shaft
135   for( int i = 0; i < n; i++ )
136   {
137     p[0] = 0;
138     p[1] = r1 * sin( i * angle );
139     p[2] = r1 * cos( i * angle );
140     points->InsertPoint( i + 3, p );
141
142     p[0] = l1;
143     points->InsertPoint( i + 3 + n, p );
144   }
145
146   // insert the last cells outside a loop
147   {
148     c3[0] = 0;
149     c3[1] = 3;
150     c3[2] = 3 + n - 1;
151     polys->InsertNextCell( 3, c3 );
152
153     c4[0] = 3;
154     c4[1] = 3 + n - 1;
155     c4[2] = 3 + 2 * n - 1;
156     c4[3] = 3 + n;
157     polys->InsertNextCell( 4, c4 );
158   }
159   for( int i = 0; i < n - 1; i++ )
160   {
161     c3[0] = 0;
162     c3[1] = i + 3;
163     c3[2] = i + 4;
164     polys->InsertNextCell( 3, c3 );
165
166     c4[0] = i + 3;
167     c4[1] = i + 4;
168     c4[2] = i + 4 + n;
169     c4[3] = i + 3 + n;
170     polys->InsertNextCell( 4, c4 );
171   }
172
173   // cone
174   for( int i = 0; i < n; i++ )
175   {
176     p[0] = l1;
177     p[1] = r2 * sin( i * angle );
178     p[2] = r2 * cos( i * angle );
179     points->InsertPoint( i + 3 + 2 * n, p );
180   }
181
182   // insert the last cells outside a loop
183   {
184     c3[0] = 1;
185     c3[1] = 3 + 2 * n;
186     c3[2] = 3 + 2 * n + n - 1;
187     polys->InsertNextCell( 3, c3 );
188
189     c3[0] = 2;
190     polys->InsertNextCell( 3, c3 );
191   }
192   for( int i = 0; i < n - 1; i++ )
193   {
194     c3[0] = 1;
195     c3[1] = 3 + i + 2 * n;
196     c3[2] = 3 + i + 2 * n + 1;
197     polys->InsertNextCell( 3, c3 );
198
199     c3[0] = 2;
200     polys->InsertNextCell( 3, c3 );
201   }
202
203   vtkPolyData* aPolyData = vtkPolyData::New();
204
205   aPolyData->SetPoints(points);
206   points->Delete();
207
208   aPolyData->SetPolys(polys);
209   polys->Delete();
210
211   return aPolyData;
212 }
213
214 void GetFaceParams( vtkCell* theFace, double theNormal[3], double& theSize ) 
215 {
216   vtkPoints* aPoints = theFace->GetPoints();
217
218   // here we get first 3 points from the face and calculate the normal as a cross-product of vectors
219   // double x0 = aPoints->GetPoint(0)[0], y0 = aPoints->GetPoint(0)[1], z0 = aPoints->GetPoint(0)[2];
220   // double x1 = aPoints->GetPoint(1)[0], y1 = aPoints->GetPoint(1)[1], z1 = aPoints->GetPoint(1)[2];
221   // double x2 = aPoints->GetPoint(2)[0], y2 = aPoints->GetPoint(2)[1], z2 = aPoints->GetPoint(2)[2];
222
223   // theNormal[0] = ( y1 - y0 ) * ( z2 - z0 ) - ( z1 - z0 ) * ( y2 - y0 );
224   // theNormal[1] = ( z1 - z0 ) * ( x2 - x0 ) - ( x1 - x0 ) * ( z2 - z0 );
225   // theNormal[2] = ( x1 - x0 ) * ( y2 - y0 ) - ( y1 - y0 ) * ( x2 - x0 );
226
227   // issue #18665: Polyhedron volume calculation
228   vtkPolygon::ComputeNormal( aPoints, theNormal );
229
230   double* aBounds = theFace->GetBounds();
231   theSize = pow( pow( aBounds[1] - aBounds[0], 2 ) +
232                  pow( aBounds[3] - aBounds[2], 2 ) +
233                  pow( aBounds[5] - aBounds[4], 2 ), 0.5 );
234 }
235
236 /*!
237  * Execute method. Output calculation.
238  */
239 int SMESH_FaceOrientationFilter::RequestData(
240   vtkInformation *request,
241   vtkInformationVector **inputVector,
242   vtkInformationVector *outputVector)
243 {
244   // get the info objects
245   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
246   vtkInformation *outInfo = outputVector->GetInformationObject(0);
247
248   // get the input and output
249   vtkDataSet *input = vtkDataSet::SafeDownCast(
250     inInfo->Get(vtkDataObject::DATA_OBJECT()));
251   vtkPolyData *output = vtkPolyData::SafeDownCast(
252     outInfo->Get(vtkDataObject::DATA_OBJECT()));
253
254   myFacePolyData->Initialize();
255   myFacePolyData->ShallowCopy(input);
256
257   vtkCellArray* aFaces = vtkCellArray::New();
258
259   vtkFloatArray* aVectors = vtkFloatArray::New();
260   aVectors->SetNumberOfComponents(3);
261
262   int anAllFaces = 0;
263   double anAverageSize = 0;
264
265   vtkIdList* aNeighborIds = vtkIdList::New();
266
267   for(int aCellId = 0, aNbCells = input->GetNumberOfCells(); aCellId < aNbCells; aCellId++)
268   {
269     vtkCell* aCell = input->GetCell(aCellId);
270
271     if( aCell->GetNumberOfFaces() == 0 && aCell->GetNumberOfPoints() > 2 ) // cell is a face
272     {
273       double aSize, aNormal[3];
274       GetFaceParams( aCell, aNormal, aSize );
275
276       aFaces->InsertNextCell(aCell);
277       aVectors->InsertNextTuple(aNormal);
278
279       anAllFaces++;
280       anAverageSize += aSize;
281
282       continue;
283     }
284
285     for(int aFaceId = 0, aNbFaces = aCell->GetNumberOfFaces(); aFaceId < aNbFaces; aFaceId++)
286     {
287       vtkCell* aFace = aCell->GetFace(aFaceId);
288
289       input->GetCellNeighbors( aCellId, aFace->PointIds, aNeighborIds );
290       if( aNeighborIds->GetNumberOfIds() > 0 )
291         continue;
292
293       double aSize, aNormal[3];
294       GetFaceParams( aFace, aNormal, aSize );
295
296       aFaces->InsertNextCell(aFace->GetPointIds());
297       aVectors->InsertNextTuple(aNormal);
298
299       anAllFaces++;
300       anAverageSize += aSize;
301     }
302   }
303   aNeighborIds->Delete();
304
305   myFacePolyData->SetPolys(aFaces);
306   aFaces->Delete();
307
308   myFacePolyData->GetCellData()->SetScalars(0);
309   myFacePolyData->GetCellData()->SetVectors(aVectors);
310   aVectors->Delete();
311
312   if( anAllFaces == 0 )
313     return 0;
314
315   anAverageSize /= anAllFaces;
316   anAverageSize *= myOrientationScale;
317
318   myBaseGlyph->SetScaleFactor( anAverageSize );
319   myBaseGlyph->Update();
320
321   output->ShallowCopy( myBaseGlyph->GetOutput() );
322
323   return 1;
324 }
325
326 int SMESH_FaceOrientationFilter::FillInputPortInformation(int, vtkInformation *info)
327 {
328   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
329   return 1;
330 }