diff --git a/Modules/AlgorithmsExt/include/mitkUnstructuredGridClusteringFilter.h b/Modules/AlgorithmsExt/include/mitkUnstructuredGridClusteringFilter.h index 743dae16d6..d24695cf7c 100644 --- a/Modules/AlgorithmsExt/include/mitkUnstructuredGridClusteringFilter.h +++ b/Modules/AlgorithmsExt/include/mitkUnstructuredGridClusteringFilter.h @@ -1,112 +1,115 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITKUNSTRUCTUREDGRIDCLUSTERINGFILTER_h__ #define _MITKUNSTRUCTUREDGRIDCLUSTERINGFILTER_h__ #include #include #include #include #include #include #include namespace mitk { /** * @brief The UnstructuredGridClusteringFilter class * * DBSCAN algorithm: * * DBSCAN(D, eps, MinPts) * C = 0 * for each unvisited point P in dataset D * mark P as visited * N = D.regionQuery(P, eps) * if sizeof(N) < MinPts * mark P as NOISE * else * C = next cluster * expandCluster(P, N, C, eps, MinPts) * * expandCluster(P, N, C, eps, MinPts) * add P to cluster C * for each point P' in N * if P' is not visited * mark P' as visited * N' = D.regionQuery(P', eps) * if sizeof(N') >= MinPts * N = N joined with N' * if P' is not yet member of any cluster * add P' to cluster C */ class MITKALGORITHMSEXT_EXPORT UnstructuredGridClusteringFilter : public UnstructuredGridToUnstructuredGridFilter { public: mitkClassMacro(UnstructuredGridClusteringFilter, UnstructuredGridToUnstructuredGridFilter) itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkSetMacro(eps, double) itkGetMacro(eps, double) itkSetMacro(MinPts, int) itkGetMacro(MinPts, int) itkSetMacro(Meshing, bool) virtual std::vector< mitk::UnstructuredGrid::Pointer> GetAllClusters(); virtual int GetNumberOfFoundClusters(); virtual void GenerateOutputInformation(); virtual void GenerateData(); protected: UnstructuredGridClusteringFilter(); virtual ~UnstructuredGridClusteringFilter(); private: void ExpandCluster(int id, vtkIdList* pointIDs, vtkPoints* cluster, vtkPoints *inpPoints); mitk::UnstructuredGrid::Pointer m_UnstructGrid; std::vector< vtkSmartPointer > m_Clusters; + std::vector< vtkSmartPointer > m_DistanceArrays; double m_eps; int m_MinPts; bool m_Meshing; + bool m_DistCalc; + }; } // namespace mitk #endif //_MITKUNSTRUCTUREDGRIDCLUSTERINGFILTER_h__ diff --git a/Modules/AlgorithmsExt/src/mitkUnstructuredGridClusteringFilter.cpp b/Modules/AlgorithmsExt/src/mitkUnstructuredGridClusteringFilter.cpp index 9b1f089927..ed283ec590 100644 --- a/Modules/AlgorithmsExt/src/mitkUnstructuredGridClusteringFilter.cpp +++ b/Modules/AlgorithmsExt/src/mitkUnstructuredGridClusteringFilter.cpp @@ -1,218 +1,271 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include +#include + #include #include #include #include #include #include +#include +#include +#include +#include -mitk::UnstructuredGridClusteringFilter::UnstructuredGridClusteringFilter() : m_eps(0.0), m_MinPts(0), m_Meshing(true) +mitk::UnstructuredGridClusteringFilter::UnstructuredGridClusteringFilter() : m_eps(0.0), m_MinPts(0), m_Meshing(true), m_DistCalc(false) { this->m_UnstructGrid = mitk::UnstructuredGrid::New(); } mitk::UnstructuredGridClusteringFilter::~UnstructuredGridClusteringFilter(){} std::map visited; std::map isNoise; std::map clusterMember; vtkSmartPointer pLocator; +std::vector< vtkSmartPointer > clusterVector; + +std::vector< std::vector > clustersPointsIDs; void mitk::UnstructuredGridClusteringFilter::GenerateOutputInformation() { m_UnstructGrid = this->GetOutput(); } void mitk::UnstructuredGridClusteringFilter::GenerateData() { mitk::UnstructuredGrid::Pointer inputGrid = const_cast(this->GetInput()); if(inputGrid.IsNull()) return; vtkSmartPointer vtkInpGrid = inputGrid->GetVtkUnstructuredGrid(); vtkSmartPointer inpPoints = vtkInpGrid->GetPoints(); pLocator =vtkSmartPointer::New(); - std::vector< vtkSmartPointer > clusterVector; + + vtkSmartPointer distances = vtkSmartPointer::New(); + if(inputGrid->GetVtkUnstructuredGrid()->GetPointData()->GetNumberOfArrays() > 0) + { + m_DistCalc = true; + distances = dynamic_cast(vtkInpGrid->GetPointData()->GetArray(0)); + } pLocator->SetDataSet(vtkInpGrid); pLocator->AutomaticOn(); pLocator->SetNumberOfPointsPerBucket(2); pLocator->BuildLocator(); //fill the visited map with false for checking for(int i=0; iGetNumberOfPoints();i++) { visited[i] = false; isNoise[i] = false; clusterMember[i] = false; } for(int i=0; iGetNumberOfPoints();i++) { if(!visited[i]) { visited[i] = true; //mark P as visited vtkSmartPointer idList = vtkSmartPointer::New(); //represent N pLocator->FindPointsWithinRadius(m_eps, inpPoints->GetPoint(i), idList); //N = D.regionQuery(P, eps) if(idList->GetNumberOfIds() < m_MinPts) //if sizeof(N) < MinPts { isNoise[i] = true; //mark P as NOISE } else { vtkSmartPointer cluster = vtkSmartPointer::New(); //represent a cluster clusterVector.push_back(cluster); //C = next cluster this->ExpandCluster(i,idList,cluster,inpPoints); //expandCluster(P, N, C, eps, MinPts) mod. the parameter list } } } //OUTPUT LOGIC m_Clusters = clusterVector; int numberOfClusterPoints = 0; int IdOfBiggestCluster = 0; - for(unsigned int i=0; i points = m_Clusters.at(i); - for(int j=0; jGetNumberOfPoints();j++) - { - double point[3]; - points->GetPoint(j,point); - } - if(points->GetNumberOfPoints() > numberOfClusterPoints) + for(unsigned int i=0; iGetNumberOfPoints(); - IdOfBiggestCluster = i; + vtkSmartPointer array = vtkSmartPointer::New(); + vtkSmartPointer points = m_Clusters.at(i); + array->SetNumberOfComponents(1); + array->SetNumberOfTuples(points->GetNumberOfPoints()); + for(int j=0; jGetNumberOfPoints();j++) + { + double point[3]; + points->GetPoint(j,point); + if(clustersPointsIDs.at(i).at(j)GetNumberOfPoints()) + { + if(distances->GetValue(clustersPointsIDs.at(i).at(j)) > 0.001) + { + double dist[1] = {distances->GetValue(clustersPointsIDs.at(i).at(j))}; + array->SetTuple(j, dist); + } + else + { + double dist[1] = {0.0}; + array->SetTuple(j, dist); + } + } + } + m_DistanceArrays.push_back(array); + if(points->GetNumberOfPoints() > numberOfClusterPoints) + { + numberOfClusterPoints = points->GetNumberOfPoints(); + IdOfBiggestCluster = i; + } } } vtkSmartPointer biggestCluster = vtkSmartPointer::New(); vtkSmartPointer points = vtkSmartPointer::New(); points = m_Clusters.at(IdOfBiggestCluster); vtkSmartPointer verts = vtkSmartPointer::New(); verts->GetPointIds()->SetNumberOfIds(m_Clusters.at(IdOfBiggestCluster)->GetNumberOfPoints()); for(int i=0; iGetNumberOfPoints(); i++) { verts->GetPointIds()->SetId(i,i); } biggestCluster->Allocate(1); biggestCluster->InsertNextCell(verts->GetCellType(), verts->GetPointIds()); biggestCluster->SetPoints(m_Clusters.at(IdOfBiggestCluster)); if(m_Meshing) { vtkSmartPointer mesher = vtkSmartPointer::New(); mesher->SetInputData(biggestCluster); mesher->SetAlpha(0.9); mesher->Update(); vtkSmartPointer output = mesher->GetOutput(); m_UnstructGrid->SetVtkUnstructuredGrid(output); } else { m_UnstructGrid->SetVtkUnstructuredGrid(biggestCluster); } + + clusterVector.clear(); + clustersPointsIDs.clear(); } void mitk::UnstructuredGridClusteringFilter::ExpandCluster(int id, vtkIdList *pointIDs, vtkPoints* cluster, vtkPoints* inpPoints) { + std::vector x; + x.push_back(id); cluster->InsertNextPoint(inpPoints->GetPoint(id)); //add P to cluster C clusterMember[id] = true; //right? vtkSmartPointer neighbours = vtkSmartPointer::New(); //same N as in other function inpPoints->GetPoints(pointIDs,neighbours); for(int i=0; iGetNumberOfIds();i++) //for each point P' in N { if(!visited[pointIDs->GetId(i)]) //if P' is not visited { visited[pointIDs->GetId(i)] = true; //mark P' as visited vtkSmartPointer idList = vtkSmartPointer::New(); //represent N' pLocator->FindPointsWithinRadius(m_eps, inpPoints->GetPoint(pointIDs->GetId(i)), idList); //N' = D.regionQuery(P', eps) + if(idList->GetNumberOfIds() >= m_MinPts) //if sizeof(N') >= MinPts { for(int j=0; jGetNumberOfIds();j++) //N = N joined with N' { - pointIDs->InsertNextId(idList->GetId(j)); + if(idList->GetId(j)GetNumberOfPoints())//a litte bit hacked ?! + { + pointIDs->InsertNextId(idList->GetId(j)); + } } } } if(!clusterMember[pointIDs->GetId(i)]) //if P' is not yet member of any cluster { - clusterMember[pointIDs->GetId(i)] = true; - cluster->InsertNextPoint(inpPoints->GetPoint(pointIDs->GetId(i))); //add P' to cluster C + if(pointIDs->GetId(i)GetNumberOfPoints()){ + clusterMember[pointIDs->GetId(i)] = true; + x.push_back(pointIDs->GetId(i)); + cluster->InsertNextPoint(inpPoints->GetPoint(pointIDs->GetId(i))); //add P' to cluster C + } } } + + clustersPointsIDs.push_back(x); } std::vector mitk::UnstructuredGridClusteringFilter::GetAllClusters() { std::vector< mitk::UnstructuredGrid::Pointer > mitkUGridVector; for(unsigned int i=0; i cluster = vtkSmartPointer::New(); vtkSmartPointer points = m_Clusters.at(i); vtkSmartPointer verts = vtkSmartPointer::New(); verts->GetPointIds()->SetNumberOfIds(points->GetNumberOfPoints()); - for(int i=0; iGetNumberOfPoints(); i++) + for(int j=0; jGetNumberOfPoints(); j++) { - verts->GetPointIds()->SetId(i,i); + verts->GetPointIds()->SetId(j,j); } cluster->Allocate(1); cluster->InsertNextCell(verts->GetCellType(), verts->GetPointIds()); cluster->SetPoints(points); + if(m_DistCalc) + { + cluster->GetPointData()->AddArray(m_DistanceArrays.at(i)); + } mitk::UnstructuredGrid::Pointer mitkGrid = mitk::UnstructuredGrid::New(); if(m_Meshing) { vtkSmartPointer mesher = vtkSmartPointer::New(); mesher->SetInputData(cluster); mesher->SetAlpha(0.9); mesher->Update(); vtkSmartPointer output = mesher->GetOutput(); mitkGrid->SetVtkUnstructuredGrid(output); } else { mitkGrid->SetVtkUnstructuredGrid(cluster); } mitkUGridVector.push_back(mitkGrid); } return mitkUGridVector; } int mitk::UnstructuredGridClusteringFilter::GetNumberOfFoundClusters() { return m_Clusters.size(); } diff --git a/Modules/SurfaceInterpolation/mitkClusteredPlaneSuggestionFilter.cpp b/Modules/SurfaceInterpolation/mitkClusteredPlaneSuggestionFilter.cpp index a810997461..0f977fb5a9 100644 --- a/Modules/SurfaceInterpolation/mitkClusteredPlaneSuggestionFilter.cpp +++ b/Modules/SurfaceInterpolation/mitkClusteredPlaneSuggestionFilter.cpp @@ -1,96 +1,262 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ +#include + +#include +#include +#include + +#include #include +#include +#include +#include +#include #include -#include +#include #include mitk::ClusteredPlaneSuggestionFilter::ClusteredPlaneSuggestionFilter(): m_Meshing(false), m_MinPts(4), m_Eps(1.2) { this->m_MainCluster = mitk::UnstructuredGrid::New(); this->m_GeoData = mitk::GeometryData::New(); } mitk::ClusteredPlaneSuggestionFilter::~ClusteredPlaneSuggestionFilter(){} +bool myComparison(std::pair i, std::pair j){ return (i.first>j.first); } + void mitk::ClusteredPlaneSuggestionFilter::GenerateData() { mitk::UnstructuredGrid::Pointer inpGrid = const_cast(this->GetInput()); if(inpGrid.IsNull()) { MITK_ERROR << "Input or cast to UnstructuredGrid is null"; return; } +// std::cout << "NUMBER OF INPUT GRID: " << inpGrid->GetVtkUnstructuredGrid()->GetNumberOfPoints() << std::endl; + +// std::cout << "POINTDATA-SIZE OF INPUT GRID: " << inpGrid->GetVtkUnstructuredGrid()->GetPointData()->GetArray(0)->GetSize() << std::endl; + +// std::fstream ds; +// ds.open("/home/riecker/test.txt"); + +// vtkSmartPointer array = dynamic_cast(inpGrid->GetVtkUnstructuredGrid()->GetPointData()->GetArray(0)); +// for(int i=0; iGetSize();i++) +// { +// ds << "point: " << i << " distance " << array->GetValue(i) << std::endl; +// } +// ds.close(); + mitk::UnstructuredGridClusteringFilter::Pointer clusterFilter = mitk::UnstructuredGridClusteringFilter::New(); clusterFilter->SetInput(inpGrid); - clusterFilter->SetMeshing(m_Meshing); + clusterFilter->SetMeshing(false); clusterFilter->SetMinPts(m_MinPts); clusterFilter->Seteps(m_Eps); clusterFilter->Update(); - //need the get and set the vtkUnstructuredGrid instead of the mitkUnstructuredGrid, otherwise rendering error vtkSmartPointer< vtkUnstructuredGrid > vtkGrid = clusterFilter->GetOutput()->GetVtkUnstructuredGrid(); if(!vtkGrid) { MITK_ERROR << "vtkUnstructuredGrid output from clustering is null"; return; } m_MainCluster->SetVtkUnstructuredGrid(vtkGrid); m_Clusters = clusterFilter->GetAllClusters(); + std::fstream fs; + fs.open("/home/riecker/clusters.txt"); + + //test if the scalar transfer works + for(unsigned int i=0; i data = dynamic_cast(cluster->GetVtkUnstructuredGrid()->GetPointData()->GetArray(0)); + for(int j=0; jGetSize();j++) + { + fs << "Point " << j << " - Distance: " << data->GetValue(j) << std::endl; + } + } + fs.close(); + //end + + //find the avg distances of every cluster maybe a square mean for better looking at high values? + std::vector< std::pair > avgDistances; +// std::vector< double > avgDistances; + for(unsigned int i=0; i data = dynamic_cast(cluster->GetVtkUnstructuredGrid()->GetPointData()->GetArray(0)); + double avg = 0.0; + for(int j=0; jGetSize();j++) + { + avg += data->GetValue(j); + } + avgDistances.push_back(std::make_pair(avg/static_cast(data->GetSize()),i)); + } + //now sort the clusters with their distances + + //get the number of points and the id of every cluster + std::vector< std::pair > sizeIDs; + + for(unsigned int i=0; iGetVtkUnstructuredGrid()->GetNumberOfPoints(), i)); +// std::cout << "CLUSTER ID: " << i << " NUMBER OF POINTS: " << m_Clusters.at(i)->GetVtkUnstructuredGrid()->GetNumberOfPoints() << std::endl; + } + + //sort the number of points for finding the three biggest + //sizeIDs is sorted by number of points in each cluster + //avgDistances is sorted by avg distance to next edge + std::sort(sizeIDs.begin(), sizeIDs.end(), myComparison); + std::sort(avgDistances.begin(), avgDistances.end(), myComparison); + + for(unsigned int i=0; i(avgDistances.size()); + //end calc the overall mean distance + + int number = 0; //max number of biggest clusters which are used for the plane + + //if less than 3 clusters are found +// if(m_Clusters.size()<3) + number = m_Clusters.size(); +// else +// number = 3; + +// double mean = 0.0; +// for(unsigned int i=0; i(m_Clusters.size()); + +// for(unsigned int i=0; i=2) +// number = 2; + + //calc the number of clusters which distances are higher than the average +// for(unsigned int i=0; i= " << overallDistance << std::endl; +// if(avgDistances.at(i).first >= overallDistance) +// number++; +// } +// std::cout << "Number of clusters which distance is higher than the average: " << number << std::endl; + + //filter small clusters out! +// int pointsOverAll = 0; +// for(unsigned int i=0; iGetVtkUnstructuredGrid()->GetNumberOfPoints(); +// } +// int avg = pointsOverAll / m_Clusters.size(); + +// for(unsigned int i=0; i= avg) +// number++; +// else +// break; +// } + +// std::cout << "NUMBER OF CLUSTERS: " << number << std::endl; + + //Generate a pointset from UnstructuredGrid for the PlaneFitFilter: mitk::PointSet::Pointer pointset = mitk::PointSet::New(); - for(int i=0; iGetNumberOfPoints();i++) + int pointId = 0; + + for(int j=0; jGetPoint(i)[0]; - point[1] = vtkGrid->GetPoint(i)[1]; - point[2] = vtkGrid->GetPoint(i)[2]; + //Get the cluster with "id" from all clusters, "id" is saved in sizeIDs.second + //sizeIDs.first represent the number of points which is only needed for sorting the "id"s +// vtkSmartPointer tmpGrid = m_Clusters.at(avgDistances.at(j).second)->GetVtkUnstructuredGrid(); //highest distance + vtkSmartPointer tmpGrid = m_Clusters.at(sizeIDs.at(j).second)->GetVtkUnstructuredGrid(); //biggest cluster +// std::cout << "CLUSTER ID: " << avgDistances.at(j).second << " NUMBER OF POINTS: " << avgDistances.at(j).first << std::endl; + for(int i=0; iGetNumberOfPoints();i++) + { + mitk::Point3D point; + point[0] = tmpGrid->GetPoint(i)[0]; + point[1] = tmpGrid->GetPoint(i)[1]; + point[2] = tmpGrid->GetPoint(i)[2]; - pointset->InsertPoint(i,point); + pointset->InsertPoint(pointId,point); + pointId++; + } } +// std::cout << "POINTSET POINTS: " << pointset->GetSize() << std::endl; + mitk::PlaneFit::Pointer planeFilter = mitk::PlaneFit::New(); planeFilter->SetInput(pointset); planeFilter->Update(); m_GeoData = planeFilter->GetOutput(); if(m_GeoData.IsNull()) { MITK_ERROR << "GeometryData output from PlaneFit filter is null"; return; } + + m_Clusters.clear(); + avgDistances.clear(); +// mitk::PlaneGeometry* planeGeometry = dynamic_cast( planeFilter->GetOutput()->GetGeometry()); } void mitk::ClusteredPlaneSuggestionFilter::GenerateOutputInformation() { mitk::UnstructuredGrid::ConstPointer inputImage = this->GetInput(); m_MainCluster = this->GetOutput(); itkDebugMacro(<<"GenerateOutputInformation()"); if(inputImage.IsNull()) return; } diff --git a/Modules/SurfaceInterpolation/mitkClusteredPlaneSuggestionFilter.h b/Modules/SurfaceInterpolation/mitkClusteredPlaneSuggestionFilter.h index 6697e41698..843046ba10 100644 --- a/Modules/SurfaceInterpolation/mitkClusteredPlaneSuggestionFilter.h +++ b/Modules/SurfaceInterpolation/mitkClusteredPlaneSuggestionFilter.h @@ -1,112 +1,112 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITKCLUSTEREDPLANESUGGESTIONFILTER_h__ #define _MITKCLUSTEREDPLANESUGGESTIONFILTER_h__ #include #include #include namespace mitk { /** * @brief Clustering an UnstructuredGrid and calculating a Plane through it. * * The output is the biggest found cluster but you can get all clusters in a * std::vector represented by vtkPoints. Use GetClusters() the get the vector. * With GetGeoData() you get the calculated geometry as a mitk::GeometryData. * Internally the mitk::UnstructuredGridClusteringFilter is used for * clustering and after the mitk::PlaneFit for calculating the plane. * The parameters m_Meshing (Set/GetMeshing()), m_MinPts (Set/GetMinPts()) and * m_Eps (Set/GetEps()) are used for the UnstructuredGridClusteringFilter. */ - class MitkSurfaceInterpolation_EXPORT ClusteredPlaneSuggestionFilter + class MITKSURFACEINTERPOLATION_EXPORT ClusteredPlaneSuggestionFilter : public UnstructuredGridToUnstructuredGridFilter { public: mitkClassMacro(ClusteredPlaneSuggestionFilter, UnstructuredGridToUnstructuredGridFilter) itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Returns the geometry of the calculated plane from mitk::PlaneFit */ itkGetMacro(GeoData, mitk::GeometryData::Pointer) /** Returns all clusters which were found by the clustering filter */ itkGetMacro(Clusters, std::vector< mitk::UnstructuredGrid::Pointer >) /** Activate the meshing function for the returned clusters. The meshing * is needed to see the result in the 2D-renderwindows */ itkGetMacro(Meshing, bool) itkSetMacro(Meshing, bool) /** Minimal points which have to be located in the neighbourhood to define * the point as a core point. For more information see DBSCAN algorithm */ itkGetMacro(MinPts, int) itkSetMacro(MinPts, int) /** The range/neighbourhood for clustering the points. For more * information see DBSCAN algorithm */ itkGetMacro(Eps, double) itkSetMacro(Eps, double) protected: /** Constructor */ ClusteredPlaneSuggestionFilter(); /** Destructor */ virtual ~ClusteredPlaneSuggestionFilter(); /** Is called by the Update() method of the filter */ virtual void GenerateData(); /** Defines the output of the filter */ virtual void GenerateOutputInformation(); private: /** The geometry of the calculated plane */ mitk::GeometryData::Pointer m_GeoData; /** The vector which holds all found clusters */ std::vector< mitk::UnstructuredGrid::Pointer > m_Clusters; /** The biggest found cluster - the output */ mitk::UnstructuredGrid::Pointer m_MainCluster; /** Connect the points to meshes. Required for 2D rendering */ bool m_Meshing; /** Number of points required to define a core point */ int m_MinPts; /** The distance/neighbourhood for clustering */ double m_Eps; }; } // namespace mitk #endif //_MITKCLUSTEREDPLANESUGGESTIONFILTER_h__