Salome HOME
Merge from V6_4_BR 05/12/2011
[modules/visu.git] / src / OBJECT / VISU_SelectVisiblePoints.cxx
1 // Copyright (C) 2007-2011  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                    GetCompositeProjectionTransformMatrix(this->Renderer->GetTiledAspectRatio(),0,1));
124
125   // If we have more than a few query points, we grab the z-buffer for the
126   // selection region all at once and probe the resulting array.  When we
127   // have just a few points, we perform individual z-buffer queries.
128   const int SimpleQueryLimit = 25;
129   float *zPtr = NULL;
130   if (numPts > SimpleQueryLimit)
131     {
132     zPtr = this->Renderer->GetRenderWindow()->
133       GetZbufferData(selection[0], selection[2], selection[1], selection[3]);
134     }
135   
136   int abort=0;
137   vtkIdType progressInterval=numPts/20+1;
138   x[3] = 1.0;
139   for (cellId=(-1), ptId=0; ptId < numPts && !abort; ptId++)
140     {
141     // perform conversion
142     input->GetPoint(ptId,x);
143
144     // take into account translation offset (this is the only difference
145     // between this class and native vtkSelectVisiblePoints class)
146     xTrans[0] = x[0] + this->Offset[0];
147     xTrans[1] = x[1] + this->Offset[1];
148     xTrans[2] = x[2] + this->Offset[2];
149     xTrans[3] = 1.0;
150
151     matrix->MultiplyPoint(xTrans, view);
152     if (view[3] == 0.0)
153       {
154       continue;
155       }
156     this->Renderer->SetViewPoint(view[0]/view[3], view[1]/view[3],
157                                  view[2]/view[3]);
158     this->Renderer->ViewToDisplay();
159     this->Renderer->GetDisplayPoint(dx);
160     visible = 0;
161
162     if ( ! (ptId % progressInterval) ) 
163       {
164       this->UpdateProgress((double)ptId/numPts);
165       abort = this->GetAbortExecute();
166       }
167
168     // check whether visible and in selection window 
169     if ( dx[0] >= selection[0] && dx[0] <= selection[1] &&
170          dx[1] >= selection[2] && dx[1] <= selection[3] )
171       {
172       if (numPts > SimpleQueryLimit)
173         {
174         // Access the value from the captured zbuffer.  Note, we only
175         // captured a portion of the zbuffer, so we need to offset dx by
176         // the selection window.
177         z = zPtr[(int)dx[0] - selection[0]
178                  + ((int)dx[1] - selection[2])
179                  *(selection[1] - selection[0] + 1)];
180         }
181       else
182         {
183         z = this->Renderer->GetZ(static_cast<int>(dx[0]), 
184                                  static_cast<int>(dx[1]));
185         }
186       if( dx[2] < (z + this->Tolerance) ) 
187         {
188         visible = 1;
189         }
190       }
191
192     if ( (visible && !this->SelectInvisible) ||
193          (!visible && this->SelectInvisible) )
194       {
195       cellId = outPts->InsertNextPoint(x);
196       output->InsertNextCell(VTK_VERTEX, 1, &cellId);
197       outPD->CopyData(inPD,ptId,cellId);
198       }
199     }//for all points
200
201   output->SetPoints(outPts);
202   outPts->Delete();
203   output->Squeeze();
204
205   matrix->Delete();
206
207   if (zPtr)
208     {
209     delete [] zPtr;
210     }
211
212   vtkDebugMacro(<<"Selected " << cellId + 1 << " out of " 
213                 << numPts << " original points");
214
215   return 1;
216 }
217
218 void VISU_SelectVisiblePoints::PrintSelf(ostream& os, vtkIndent indent)
219 {
220   this->Superclass::PrintSelf(os,indent);
221
222   os << indent << "Offset: ("
223      << this->Offset[0] << ", "
224      << this->Offset[1] << ", "
225      << this->Offset[2] << ")\n";
226 }