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