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