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