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