CloudViewerCellPicker.cpp
Go to the documentation of this file.
00001 /*
00002  * CloudViewerCellPicker.cpp
00003  *
00004  *  Created on: Aug 21, 2018
00005  *      Author: mathieu
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 // Standard VTK macro for *New ()
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         // This code was taken from the original CellPicker with almost no
00052         // modification except for the locator and texture additions.
00053 
00054         // Intersect each cell with ray.  Keep track of one closest to
00055         // the eye (within the tolerance tol) and within the clipping range).
00056         // Note that we fudge the "closest to" (tMin+this->Tolerance) a little and
00057         // keep track of the cell with the best pick based on parametric
00058         // coordinate (pick the minimum, maximum parametric distance). This
00059         // breaks ties in a reasonable way when cells are the same distance
00060         // from the eye (like cells laying on a 2D plane).
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         // Polydata has no 3D cells
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         // Make a new p1 and p2 using the clipped t1 and t2
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         // Use the locator if one exists for this data
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                 // Stretch tMin out to the original range
00123                 if (t1 != 0.0 || t2 != 1.0)
00124                 {
00125                         tMin = t1*(1.0 - tMin) + t2*tMin;
00126                 }
00127 
00128                 // If cell is a strip, then replace cell with a sub-cell
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                         // If it is a strip, we need to iterate over the subIds
00146                         int cellType = data->GetCellType(cellId);
00147                         int useSubCells = this->HasSubCells(cellType);
00148                         if (useSubCells)
00149                         {
00150                                 // Get the pointIds for the strip and the length of the strip
00151                                 data->GetCellPoints(cellId, pointIds);
00152                                 numSubIds = this->GetNumberOfSubCells(pointIds, cellType);
00153                         }
00154 
00155                         // This will only loop once unless we need to deal with a strip
00156                         for (int subId = 0; subId < numSubIds; subId++)
00157                         {
00158                                 if (useSubCells)
00159                                 {
00160                                         // Get a sub-cell from a the strip
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                                         // Polydata can always be picked with original endpoints
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                                         // Any 3D cells need to be intersected with a line segment that
00179                                         // has been clipped with the clipping planes, in case one end is
00180                                         // actually inside the cell.
00181                                         cellPicked = this->cell_->IntersectWithLine(
00182                                                         q1, q2, tol, t, x, pcoords, newSubId);
00183 
00184                                         // Stretch t out to the original range
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 // BEGIN: Modifications from VTK 6.2
00199                                                 bool visible = true;
00200                                                 if(actor->GetProperty()->GetBackfaceCulling() ||
00201                                                    actor->GetProperty()->GetFrontfaceCulling())
00202                                                 {
00203                                                         // Get the cell weights
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                                                         // Get the interpolation weights (point is thrown away)
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                                                         // save all of these
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 // END: Modifications from VTK 6.2
00250                                         } // for all subIds
00251                                 } // if minimum, maximum
00252                         } // if a close cell
00253                 } // for all cells
00254         }
00255 
00256         // Do this if a cell was intersected
00257         if (minCellId >= 0 && tMin < this->GlobalTMin)
00258         {
00259                 this->ResetPickInfo();
00260 
00261                 // Get the cell, convert to triangle if it is a strip
00262                 vtkGenericCell *cell = this->cell_;
00263 
00264                 // If we used a locator, we already have the picked cell
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                 // Get the cell weights
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                 // Get the interpolation weights (point is thrown away)
00289                 double point[3];
00290                 cell->EvaluateLocation(minSubId, minPCoords, point, weights);
00291 
00292                 this->Mapper = mapper;
00293 
00294                 // Get the texture from the actor or the LOD
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                         // Return the texture's image data to the user
00310                         vtkImageData *image = this->Texture->GetInput();
00311                         this->DataSet = image;
00312 
00313                         // Get and check the image dimensions
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                         // Use the texture coord to set the information
00325                         double tcoord[3];
00326                         if (dimensionsAreValid &&
00327                                         this->ComputeSurfaceTCoord(data, cell, weights, tcoord))
00328                         {
00329                                 // Take the border into account when computing coordinates
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                         // Return the polydata to the user
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                         // Find the point with the maximum weight
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                         // If maximum weight is found, use it to get the PointId
00360                         if (iMaxWeight != -1)
00361                         {
00362                                 this->PointId = cell->PointIds->GetId(iMaxWeight);
00363                         }
00364                 }
00365 
00366                 // Set the mapper position
00367                 this->MapperPosition[0] = minXYZ[0];
00368                 this->MapperPosition[1] = minXYZ[1];
00369                 this->MapperPosition[2] = minXYZ[2];
00370 
00371                 // Compute the normal
00372                 if (!this->ComputeSurfaceNormal(data, cell, weights, this->MapperNormal))
00373                 {
00374                         // By default, the normal points back along view ray
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 } /* namespace rtabmap */


rtabmap
Author(s): Mathieu Labbe
autogenerated on Thu Jun 6 2019 21:59:19