Salome HOME
Merge from V5_1_main 14/05/2010
[modules/visu.git] / src / OBJECT / VISU_SelectVisiblePoints.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 //  VISU OBJECT : interactive object for VISU entities implementation
21 //  File   : VISU_SelectVisiblePoints.h
22 //  Author : Oleg UVAROV
23 //  Module : VISU
24 //
25 #include "VISU_SelectVisiblePoints.h"
26
27 #include "vtkCamera.h"
28 #include "vtkCellArray.h"
29 #include "vtkDataSet.h"
30 #include "vtkMatrix4x4.h"
31 #include "vtkInformation.h"
32 #include "vtkInformationVector.h"
33 #include "vtkObjectFactory.h"
34 #include "vtkPointData.h"
35 #include "vtkPoints.h"
36 #include "vtkPolyData.h"
37 #include "vtkRenderWindow.h"
38 #include "vtkRenderer.h"
39
40 vtkStandardNewMacro(VISU_SelectVisiblePoints);
41
42 // Instantiate object with no renderer; window selection turned off; 
43 // tolerance set to 0.01; and select invisible off.
44 VISU_SelectVisiblePoints::VISU_SelectVisiblePoints()
45 {
46   this->Offset[0] = this->Offset[1] = this->Offset[2] = 0.0;
47 }
48
49 VISU_SelectVisiblePoints::~VISU_SelectVisiblePoints()
50 {
51 }
52
53 int VISU_SelectVisiblePoints::RequestData(
54   vtkInformation *vtkNotUsed(request),
55   vtkInformationVector **inputVector,
56   vtkInformationVector *outputVector)
57 {
58   // get the info objects
59   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
60   vtkInformation *outInfo = outputVector->GetInformationObject(0);
61
62   // get the input and ouptut
63   vtkDataSet *input = vtkDataSet::SafeDownCast(
64     inInfo->Get(vtkDataObject::DATA_OBJECT()));
65   vtkPolyData *output = vtkPolyData::SafeDownCast(
66     outInfo->Get(vtkDataObject::DATA_OBJECT()));
67
68   vtkIdType ptId, cellId;
69   int visible;
70   vtkPoints *outPts;
71   vtkCellArray *outputVertices;
72   vtkPointData *inPD=input->GetPointData();
73   vtkPointData *outPD=output->GetPointData();
74   vtkIdType numPts=input->GetNumberOfPoints();
75   double x[4], xTrans[4];
76   double dx[3], z;
77   int selection[4];
78   
79   if ( this->Renderer == NULL )
80     {
81     vtkErrorMacro(<<"Renderer must be set");
82     return 0;
83     }
84
85   if ( numPts < 1 )
86     {
87     return 0;
88     }
89   
90   outPts = vtkPoints::New();
91   outPts->Allocate(numPts/2+1);
92   outPD->CopyAllocate(inPD);
93
94   outputVertices = vtkCellArray::New();
95   output->SetVerts(outputVertices);
96   outputVertices->Delete();
97
98   int *size = this->Renderer->GetRenderWindow()->GetSize();
99
100   // specify a selection window to avoid querying 
101   if ( this->SelectionWindow )
102     {
103     for (int i=0; i<4; i++)
104       {
105       selection[i] = this->Selection[i];
106       }
107     }
108   else
109     {
110     selection[0] = selection[2] = 0;
111     selection[1] = size[0] - 1;
112     selection[3] = size[1] - 1;
113     }
114
115   // Grab the composite perspective transform.  This matrix is used to convert
116   // each point to view coordinates.  vtkRenderer provides a WorldToView()
117   // method but it computes the composite perspective transform each time
118   // WorldToView() is called.  This is expensive, so we get the matrix once
119   // and handle the transformation ourselves.
120   vtkMatrix4x4 *matrix = vtkMatrix4x4::New();
121   double view[4];
122   matrix->DeepCopy(this->Renderer->GetActiveCamera()->
123                    GetCompositePerspectiveTransformMatrix(
124                      this->Renderer->GetTiledAspectRatio(),0,1));
125
126   // If we have more than a few query points, we grab the z-buffer for the
127   // selection region all at once and probe the resulting array.  When we
128   // have just a few points, we perform individual z-buffer queries.
129   const int SimpleQueryLimit = 25;
130   float *zPtr = NULL;
131   if (numPts > SimpleQueryLimit)
132     {
133     zPtr = this->Renderer->GetRenderWindow()->
134       GetZbufferData(selection[0], selection[2], selection[1], selection[3]);
135     }
136   
137   int abort=0;
138   vtkIdType progressInterval=numPts/20+1;
139   x[3] = 1.0;
140   for (cellId=(-1), ptId=0; ptId < numPts && !abort; ptId++)
141     {
142     // perform conversion
143     input->GetPoint(ptId,x);
144
145     // take into account translation offset (this is the only difference
146     // between this class and native vtkSelectVisiblePoints class)
147     xTrans[0] = x[0] + this->Offset[0];
148     xTrans[1] = x[1] + this->Offset[1];
149     xTrans[2] = x[2] + this->Offset[2];
150     xTrans[3] = 1.0;
151
152     matrix->MultiplyPoint(xTrans, view);
153     if (view[3] == 0.0)
154       {
155       continue;
156       }
157     this->Renderer->SetViewPoint(view[0]/view[3], view[1]/view[3],
158                                  view[2]/view[3]);
159     this->Renderer->ViewToDisplay();
160     this->Renderer->GetDisplayPoint(dx);
161     visible = 0;
162
163     if ( ! (ptId % progressInterval) ) 
164       {
165       this->UpdateProgress((double)ptId/numPts);
166       abort = this->GetAbortExecute();
167       }
168
169     // check whether visible and in selection window 
170     if ( dx[0] >= selection[0] && dx[0] <= selection[1] &&
171          dx[1] >= selection[2] && dx[1] <= selection[3] )
172       {
173       if (numPts > SimpleQueryLimit)
174         {
175         // Access the value from the captured zbuffer.  Note, we only
176         // captured a portion of the zbuffer, so we need to offset dx by
177         // the selection window.
178         z = zPtr[(int)dx[0] - selection[0]
179                  + ((int)dx[1] - selection[2])
180                  *(selection[1] - selection[0] + 1)];
181         }
182       else
183         {
184         z = this->Renderer->GetZ(static_cast<int>(dx[0]), 
185                                  static_cast<int>(dx[1]));
186         }
187       if( dx[2] < (z + this->Tolerance) ) 
188         {
189         visible = 1;
190         }
191       }
192
193     if ( (visible && !this->SelectInvisible) ||
194          (!visible && this->SelectInvisible) )
195       {
196       cellId = outPts->InsertNextPoint(x);
197       output->InsertNextCell(VTK_VERTEX, 1, &cellId);
198       outPD->CopyData(inPD,ptId,cellId);
199       }
200     }//for all points
201
202   output->SetPoints(outPts);
203   outPts->Delete();
204   output->Squeeze();
205
206   matrix->Delete();
207
208   if (zPtr)
209     {
210     delete [] zPtr;
211     }
212
213   vtkDebugMacro(<<"Selected " << cellId + 1 << " out of " 
214                 << numPts << " original points");
215
216   return 1;
217 }
218
219 void VISU_SelectVisiblePoints::PrintSelf(ostream& os, vtkIndent indent)
220 {
221   this->Superclass::PrintSelf(os,indent);
222
223   os << indent << "Offset: ("
224      << this->Offset[0] << ", "
225      << this->Offset[1] << ", "
226      << this->Offset[2] << ")\n";
227 }