Salome HOME
Merge from V5_1_3_BR branch (07/12/09)
[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 vtkPolyData* SMESH_FaceOrientationFilter::CreateArrowPolyData()
95 {
96   vtkPoints* points = vtkPoints::New();
97   vtkCellArray* polys = vtkCellArray::New();
98
99   float l1 = 0.8;
100   float l2 = 1.0;
101   int n = 16;
102   float r1 = 0.04;
103   float r2 = 0.08;
104   float angle = 2. * PI / n;
105   float p[3];
106   vtkIdType c3[3];
107   vtkIdType c4[4];
108
109   float p0[3] = { 0.0, 0.0, 0.0 };
110   float p1[3] = {  l1, 0.0, 0.0 };
111   float p2[3] = {  l2, 0.0, 0.0 };
112
113   points->InsertPoint( 0, p0 );
114   points->InsertPoint( 1, p1 );
115   points->InsertPoint( 2, p2 );
116
117   // shaft
118   for( int i = 0; i < n; i++ )
119   {
120     p[0] = 0;
121     p[1] = r1 * sin( i * angle );
122     p[2] = r1 * cos( i * angle );
123     points->InsertPoint( i + 3, p );
124
125     p[0] = l1;
126     points->InsertPoint( i + 3 + n, p );
127   }
128
129   // insert the last cells outside a loop
130   {
131     c3[0] = 0;
132     c3[1] = 3;
133     c3[2] = 3 + n - 1;
134     polys->InsertNextCell( 3, c3 );
135
136     c4[0] = 3;
137     c4[1] = 3 + n - 1;
138     c4[2] = 3 + 2 * n - 1;
139     c4[3] = 3 + n;
140     polys->InsertNextCell( 4, c4 );
141   }
142   for( int i = 0; i < n - 1; i++ )
143   {
144     c3[0] = 0;
145     c3[1] = i + 3;
146     c3[2] = i + 4;
147     polys->InsertNextCell( 3, c3 );
148
149     c4[0] = i + 3;
150     c4[1] = i + 4;
151     c4[2] = i + 4 + n;
152     c4[3] = i + 3 + n;
153     polys->InsertNextCell( 4, c4 );
154   }
155
156   // cone
157   for( int i = 0; i < n; i++ )
158   {
159     p[0] = l1;
160     p[1] = r2 * sin( i * angle );
161     p[2] = r2 * cos( i * angle );
162     points->InsertPoint( i + 3 + 2 * n, p );
163   }
164
165   // insert the last cells outside a loop
166   {
167     c3[0] = 1;
168     c3[1] = 3 + 2 * n;
169     c3[2] = 3 + 2 * n + n - 1;
170     polys->InsertNextCell( 3, c3 );
171
172     c3[0] = 2;
173     polys->InsertNextCell( 3, c3 );
174   }
175   for( int i = 0; i < n - 1; i++ )
176   {
177     c3[0] = 1;
178     c3[1] = 3 + i + 2 * n;
179     c3[2] = 3 + i + 2 * n + 1;
180     polys->InsertNextCell( 3, c3 );
181
182     c3[0] = 2;
183     polys->InsertNextCell( 3, c3 );
184   }
185
186   vtkPolyData* aPolyData = vtkPolyData::New();
187
188   aPolyData->SetPoints(points);
189   points->Delete();
190
191   aPolyData->SetPolys(polys);
192   polys->Delete();
193
194   return aPolyData;
195 }
196
197 void GetFaceParams( vtkCell* theFace, double theNormal[3], double& theSize ) 
198 {
199   vtkPoints* aPoints = theFace->GetPoints();
200
201   // here we get first 3 points from the face and calculate the normal as a cross-product of vectors
202   double x0 = aPoints->GetPoint(0)[0], y0 = aPoints->GetPoint(0)[1], z0 = aPoints->GetPoint(0)[2];
203   double x1 = aPoints->GetPoint(1)[0], y1 = aPoints->GetPoint(1)[1], z1 = aPoints->GetPoint(1)[2];
204   double x2 = aPoints->GetPoint(2)[0], y2 = aPoints->GetPoint(2)[1], z2 = aPoints->GetPoint(2)[2];
205
206   theNormal[0] = ( y1 - y0 ) * ( z2 - z0 ) - ( z1 - z0 ) * ( y2 - y0 );
207   theNormal[1] = ( z1 - z0 ) * ( x2 - x0 ) - ( x1 - x0 ) * ( z2 - z0 );
208   theNormal[2] = ( x1 - x0 ) * ( y2 - y0 ) - ( y1 - y0 ) * ( x2 - x0 );
209
210   double* aBounds = theFace->GetBounds();
211   theSize = pow( pow( aBounds[1] - aBounds[0], 2 ) +
212                  pow( aBounds[3] - aBounds[2], 2 ) +
213                  pow( aBounds[5] - aBounds[4], 2 ), 0.5 );
214 }
215
216 /*!
217  * Execute method. Output calculation.
218  */
219 int SMESH_FaceOrientationFilter::RequestData(
220   vtkInformation *request,
221   vtkInformationVector **inputVector,
222   vtkInformationVector *outputVector)
223 {
224   // get the info objects
225   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
226   vtkInformation *outInfo = outputVector->GetInformationObject(0);
227
228   // get the input and ouptut
229   vtkDataSet *input = vtkDataSet::SafeDownCast(
230     inInfo->Get(vtkDataObject::DATA_OBJECT()));
231   vtkPolyData *output = vtkPolyData::SafeDownCast(
232     outInfo->Get(vtkDataObject::DATA_OBJECT()));
233
234   myFacePolyData->Initialize();
235   myFacePolyData->ShallowCopy(input);
236
237   vtkCellArray* aFaces = vtkCellArray::New();
238
239   vtkFloatArray* aVectors = vtkFloatArray::New();
240   aVectors->SetNumberOfComponents(3);
241
242   int anAllFaces = 0;
243   double anAverageSize = 0;
244
245   vtkIdList* aNeighborIds = vtkIdList::New();
246
247   for(int aCellId = 0, aNbCells = input->GetNumberOfCells(); aCellId < aNbCells; aCellId++)
248   {
249     vtkCell* aCell = input->GetCell(aCellId);
250
251     if( aCell->GetNumberOfFaces() == 0 && aCell->GetNumberOfPoints() > 2 ) // cell is a face
252     {
253       double aSize, aNormal[3];
254       GetFaceParams( aCell, aNormal, aSize );
255
256       aFaces->InsertNextCell(aCell);
257       aVectors->InsertNextTuple(aNormal);
258
259       anAllFaces++;
260       anAverageSize += aSize;
261
262       continue;
263     }
264
265     for(int aFaceId = 0, aNbFaces = aCell->GetNumberOfFaces(); aFaceId < aNbFaces; aFaceId++)
266     {
267       vtkCell* aFace = aCell->GetFace(aFaceId);
268
269       input->GetCellNeighbors( aCellId, aFace->PointIds, aNeighborIds );
270       if( aNeighborIds->GetNumberOfIds() > 0 )
271         continue;
272
273       double aSize, aNormal[3];
274       GetFaceParams( aFace, aNormal, aSize );
275
276       aFaces->InsertNextCell(aFace->GetPointIds());
277       aVectors->InsertNextTuple(aNormal);
278
279       anAllFaces++;
280       anAverageSize += aSize;
281     }
282   }
283   aNeighborIds->Delete();
284
285   myFacePolyData->SetPolys(aFaces);
286   aFaces->Delete();
287
288   myFacePolyData->GetCellData()->SetScalars(0);
289   myFacePolyData->GetCellData()->SetVectors(aVectors);
290   aVectors->Delete();
291
292   if( anAllFaces == 0 )
293     return 0;
294
295   anAverageSize /= anAllFaces;
296   anAverageSize *= myOrientationScale;
297
298   myBaseGlyph->SetScaleFactor( anAverageSize );
299   myBaseGlyph->Update();
300
301   output->ShallowCopy( myBaseGlyph->GetOutput() );
302
303   return 1;
304 }
305
306 int SMESH_FaceOrientationFilter::FillInputPortInformation(int, vtkInformation *info)
307 {
308   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
309   return 1;
310 }