00001
00002
00003
00004
00005
00006
00007
00008 #include "rtabmap/gui/CloudViewerCellPicker.h"
00009
00010 #include <vtkImageData.h>
00011 #include <vtkRenderer.h>
00012 #include <vtkAbstractPicker.h>
00013 #include <vtkPicker.h>
00014 #include <vtkAbstractCellLocator.h>
00015 #include <vtkIdList.h>
00016 #include <vtkCellPicker.h>
00017 #include <vtkLODProp3D.h>
00018 #include <vtkMapper.h>
00019 #include <vtkGenericCell.h>
00020 #include <vtkMath.h>
00021 #include <vtkTexture.h>
00022 #include <vtkObjectFactory.h>
00023 #include <vtkSmartPointer.h>
00024 #include <vtkPoints.h>
00025 #include <vtkProperty.h>
00026
00027 namespace rtabmap {
00028
00029
00030 vtkStandardNewMacro (CloudViewerCellPicker);
00031
00032 CloudViewerCellPicker::CloudViewerCellPicker()
00033 {
00034 cell_ = vtkGenericCell::New();
00035 pointIds_ = vtkIdList::New();
00036 }
00037
00038 CloudViewerCellPicker::~CloudViewerCellPicker()
00039 {
00040 cell_->Delete();
00041 pointIds_->Delete();
00042 }
00043
00044 double CloudViewerCellPicker::IntersectActorWithLine(const double p1[3],
00045 const double p2[3],
00046 double t1, double t2,
00047 double tol,
00048 vtkProp3D *prop,
00049 vtkMapper *mapper)
00050 {
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 vtkDataSet *data = mapper->GetInput();
00063 double tMin = VTK_DOUBLE_MAX;
00064 double minPCoords[3];
00065 double pDistMin = VTK_DOUBLE_MAX;
00066 vtkIdType minCellId = -1;
00067 int minSubId = -1;
00068 double minXYZ[3];
00069 minXYZ[0] = minXYZ[1] = minXYZ[2] = 0.0;
00070 double ray[3] = {p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]};
00071 vtkMath::Normalize(ray);
00072 vtkActor * actor = vtkActor::SafeDownCast(prop);
00073
00074
00075 int isPolyData = data->IsA("vtkPolyData");
00076
00077 vtkCollectionSimpleIterator iter;
00078 vtkAbstractCellLocator *locator = 0;
00079 this->Locators->InitTraversal(iter);
00080 while ( (locator = static_cast<vtkAbstractCellLocator *>(
00081 this->Locators->GetNextItemAsObject(iter))) )
00082 {
00083 if (locator->GetDataSet() == data)
00084 {
00085 break;
00086 }
00087 }
00088
00089
00090 double q1[3], q2[3];
00091 q1[0] = p1[0]; q1[1] = p1[1]; q1[2] = p1[2];
00092 q2[0] = p2[0]; q2[1] = p2[1]; q2[2] = p2[2];
00093 if (t1 != 0.0 || t2 != 1.0)
00094 {
00095 for (int j = 0; j < 3; j++)
00096 {
00097 q1[j] = p1[j]*(1.0 - t1) + p2[j]*t1;
00098 q2[j] = p1[j]*(1.0 - t2) + p2[j]*t2;
00099 }
00100 }
00101
00102
00103 if (locator)
00104 {
00105 vtkSmartPointer<vtkPoints> intersectPoints = vtkSmartPointer<vtkPoints>::New();
00106 vtkSmartPointer<vtkIdList> intersectCells = vtkSmartPointer<vtkIdList>::New();
00107
00108 locator->IntersectWithLine(q1, q2, intersectPoints, intersectCells);
00109 for(int i = 0; i < intersectPoints->GetNumberOfPoints(); i++ )
00110 {
00111 double intersection[3];
00112 intersectPoints->GetPoint(i, intersection);
00113 }
00114
00115 if (!locator->IntersectWithLine(q1, q2, tol, tMin, minXYZ,
00116 minPCoords, minSubId, minCellId,
00117 this->cell_))
00118 {
00119 return VTK_DOUBLE_MAX;
00120 }
00121
00122
00123 if (t1 != 0.0 || t2 != 1.0)
00124 {
00125 tMin = t1*(1.0 - tMin) + t2*tMin;
00126 }
00127
00128
00129 this->SubCellFromCell(this->cell_, minSubId);
00130 }
00131 else
00132 {
00133 vtkIdList *pointIds = this->pointIds_;
00134 vtkIdType numCells = data->GetNumberOfCells();
00135
00136 for (vtkIdType cellId = 0; cellId < numCells; cellId++)
00137 {
00138 double t;
00139 double x[3];
00140 double pcoords[3];
00141 pcoords[0] = pcoords[1] = pcoords[2] = 0;
00142 int newSubId = -1;
00143 int numSubIds = 1;
00144
00145
00146 int cellType = data->GetCellType(cellId);
00147 int useSubCells = this->HasSubCells(cellType);
00148 if (useSubCells)
00149 {
00150
00151 data->GetCellPoints(cellId, pointIds);
00152 numSubIds = this->GetNumberOfSubCells(pointIds, cellType);
00153 }
00154
00155
00156 for (int subId = 0; subId < numSubIds; subId++)
00157 {
00158 if (useSubCells)
00159 {
00160
00161 this->GetSubCell(data, pointIds, subId, cellType, this->cell_);
00162 }
00163 else
00164 {
00165 data->GetCell(cellId, this->cell_);
00166 }
00167
00168 int cellPicked = 0;
00169 if (isPolyData)
00170 {
00171
00172 cellPicked = this->cell_->IntersectWithLine(
00173 const_cast<double *>(p1), const_cast<double *>(p2),
00174 tol, t, x, pcoords, newSubId);
00175 }
00176 else
00177 {
00178
00179
00180
00181 cellPicked = this->cell_->IntersectWithLine(
00182 q1, q2, tol, t, x, pcoords, newSubId);
00183
00184
00185 if (t1 != 0.0 || t2 != 1.0)
00186 {
00187 t = t1*(1.0 - t) + t2*t;
00188 }
00189 }
00190
00191 if (cellPicked && t <= (tMin + this->Tolerance) && t >= t1 && t <= t2)
00192 {
00193 double pDist = this->cell_->GetParametricDistance(pcoords);
00194 if (pDist < pDistMin || (pDist == pDistMin && t < tMin))
00195 {
00197
00199 bool visible = true;
00200 if(actor->GetProperty()->GetBackfaceCulling() ||
00201 actor->GetProperty()->GetFrontfaceCulling())
00202 {
00203
00204 vtkIdType numPoints = this->cell_->GetNumberOfPoints();
00205 double *weights = new double[numPoints];
00206 for (vtkIdType i = 0; i < numPoints; i++)
00207 {
00208 weights[i] = 0;
00209 }
00210
00211
00212 double point[3] = {0.0,0.0,0.0};
00213 this->cell_->EvaluateLocation(minSubId, minPCoords, point, weights);
00214
00215 double normal[3] = {0.0,0.0,0.0};
00216
00217 if (this->ComputeSurfaceNormal(data, this->cell_, weights, normal))
00218 {
00219 if(actor->GetProperty()->GetBackfaceCulling())
00220 {
00221 visible = ray[0]*normal[0] + ray[1]*normal[1] + ray[2]*normal[2] <= 0;
00222 }
00223 else
00224 {
00225 visible = ray[0]*normal[0] + ray[1]*normal[1] + ray[2]*normal[2] >= 0;
00226 }
00227 }
00228 delete [] weights;
00229 }
00230 if(visible)
00231 {
00232 tMin = t;
00233 pDistMin = pDist;
00234
00235 minCellId = cellId;
00236 minSubId = newSubId;
00237 if (useSubCells)
00238 {
00239 minSubId = subId;
00240 }
00241 for (int k = 0; k < 3; k++)
00242 {
00243 minXYZ[k] = x[k];
00244 minPCoords[k] = pcoords[k];
00245 }
00246 }
00248
00250 }
00251 }
00252 }
00253 }
00254 }
00255
00256
00257 if (minCellId >= 0 && tMin < this->GlobalTMin)
00258 {
00259 this->ResetPickInfo();
00260
00261
00262 vtkGenericCell *cell = this->cell_;
00263
00264
00265 if (!locator)
00266 {
00267 int cellType = data->GetCellType(minCellId);
00268
00269 if (this->HasSubCells(cellType))
00270 {
00271 data->GetCellPoints(minCellId, this->pointIds_);
00272 this->GetSubCell(data, this->pointIds_, minSubId, cellType, cell);
00273 }
00274 else
00275 {
00276 data->GetCell(minCellId, cell);
00277 }
00278 }
00279
00280
00281 vtkIdType numPoints = cell->GetNumberOfPoints();
00282 double *weights = new double[numPoints];
00283 for (vtkIdType i = 0; i < numPoints; i++)
00284 {
00285 weights[i] = 0;
00286 }
00287
00288
00289 double point[3];
00290 cell->EvaluateLocation(minSubId, minPCoords, point, weights);
00291
00292 this->Mapper = mapper;
00293
00294
00295 vtkActor *actor = 0;
00296 vtkLODProp3D *lodActor = 0;
00297 if ( (actor = vtkActor::SafeDownCast(prop)) )
00298 {
00299 this->Texture = actor->GetTexture();
00300 }
00301 else if ( (lodActor = vtkLODProp3D::SafeDownCast(prop)) )
00302 {
00303 int lodId = lodActor->GetPickLODID();
00304 lodActor->GetLODTexture(lodId, &this->Texture);
00305 }
00306
00307 if (this->PickTextureData && this->Texture)
00308 {
00309
00310 vtkImageData *image = this->Texture->GetInput();
00311 this->DataSet = image;
00312
00313
00314 int extent[6];
00315 image->GetExtent(extent);
00316 int dimensionsAreValid = 1;
00317 int dimensions[3];
00318 for (int i = 0; i < 3; i++)
00319 {
00320 dimensions[i] = extent[2*i + 1] - extent[2*i] + 1;
00321 dimensionsAreValid = (dimensionsAreValid && dimensions[i] > 0);
00322 }
00323
00324
00325 double tcoord[3];
00326 if (dimensionsAreValid &&
00327 this->ComputeSurfaceTCoord(data, cell, weights, tcoord))
00328 {
00329
00330 double x[3];
00331 x[0] = extent[0] + tcoord[0]*dimensions[0] - 0.5;
00332 x[1] = extent[2] + tcoord[1]*dimensions[1] - 0.5;
00333 x[2] = extent[4] + tcoord[2]*dimensions[2] - 0.5;
00334
00335 this->SetImageDataPickInfo(x, extent);
00336 }
00337 }
00338 else
00339 {
00340
00341 this->DataSet = data;
00342 this->CellId = minCellId;
00343 this->SubId = minSubId;
00344 this->PCoords[0] = minPCoords[0];
00345 this->PCoords[1] = minPCoords[1];
00346 this->PCoords[2] = minPCoords[2];
00347
00348
00349 double maxWeight = 0;
00350 vtkIdType iMaxWeight = -1;
00351 for (vtkIdType i = 0; i < numPoints; i++)
00352 {
00353 if (weights[i] > maxWeight)
00354 {
00355 iMaxWeight = i;
00356 }
00357 }
00358
00359
00360 if (iMaxWeight != -1)
00361 {
00362 this->PointId = cell->PointIds->GetId(iMaxWeight);
00363 }
00364 }
00365
00366
00367 this->MapperPosition[0] = minXYZ[0];
00368 this->MapperPosition[1] = minXYZ[1];
00369 this->MapperPosition[2] = minXYZ[2];
00370
00371
00372 if (!this->ComputeSurfaceNormal(data, cell, weights, this->MapperNormal))
00373 {
00374
00375 this->MapperNormal[0] = p1[0] - p2[0];
00376 this->MapperNormal[1] = p1[1] - p2[1];
00377 this->MapperNormal[2] = p1[2] - p2[2];
00378 vtkMath::Normalize(this->MapperNormal);
00379 }
00380
00381 delete [] weights;
00382 }
00383
00384 return tMin;
00385 }
00386
00387 }