We can use vtkImplicitPolyDataDistance to calculate the distance from a point to the target polydata. It’s better than calculating the distance by iterating to the search point.

The following example puts a sphere that radius is 1 and origin is (0, 0, 0) in the renderer. Our test point is (1.5, 0, 0), so the ideal distance is 0.5, but the resolution of the sphere can bring impact to the final result.

#include <vtkVersion.h>
#include <vtkImplicitPolyDataDistance.h>


#include <vtkActor.h>
#include <vtkFloatArray.h>
#include <vtkPointData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkLineSource.h>

#include "../share/tool.h"

int main(int, char *[])
{
    vtkSmartPointer<vtkSphereSource> sphereSource =
    vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->SetCenter(0.0, 0.0, 0.0);
    sphereSource->SetRadius(1.0f);
    sphereSource->Update();

    vtkSmartPointer<vtkPolyDataMapper> sphereMapper =
    vtkSmartPointer<vtkPolyDataMapper>::New();
    sphereMapper->SetInputConnection( sphereSource->GetOutputPort() );
    sphereMapper->ScalarVisibilityOff();

    vtkSmartPointer<vtkActor> sphereActor =
    vtkSmartPointer<vtkActor>::New();

    sphereActor->SetMapper( sphereMapper );
    sphereActor->GetProperty()->SetOpacity(.3);
    sphereActor->GetProperty()->SetColor(1,0,0);

    vtkSmartPointer<vtkImplicitPolyDataDistance> implicitPolyDataDistance =
    vtkSmartPointer<vtkImplicitPolyDataDistance>::New();
    implicitPolyDataDistance->SetInput(sphereSource->GetOutput());

    PointStruct pt0( 1.5, 0, 0 ), closetPoint;
    double signedDistance = implicitPolyDataDistance->EvaluateFunctionAndGetClosestPoint( pt0.point,
                                                                                        closetPoint.point );
    vtkSmartPointer<vtkLineSource> lineSource = vtkSmartPointer<vtkLineSource>::New();
    lineSource->SetPoint1( pt0.point );
    lineSource->SetPoint2( closetPoint.point );
    lineSource->Update();
    vtkSmartPointer<vtkPolyDataMapper> lineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    lineMapper->SetInputData( lineSource->GetOutput() );
    vtkSmartPointer<vtkActor> lineActor = vtkSmartPointer<vtkActor>::New();
    lineActor->SetMapper( lineMapper );

    cout << "signedDistance: " << signedDistance << endl;
    cout << "closetPoint: " << closetPoint;

    // ========= compare with test result =========
    vtkPolyData *sPd = sphereSource->GetOutput();
    double absDis = VTK_DOUBLE_MAX;
    for( int i = 0; i < sPd->GetNumberOfPoints(); ++i )
    {
      PointStruct pt( sPd->GetPoint( i ) );
      PointStruct vec = pt - pt0;
      if( absDis > vec.Length() )
      {
          absDis = vec.Length();
      }
    }
    cout << "absDis: " << absDis << endl;
    // ======== finish: compare ==========

    vtkSmartPointer<vtkRenderer> renderer =
    vtkSmartPointer<vtkRenderer>::New();
    renderer->AddViewProp(sphereActor);
    renderer->AddActor( lineActor );

    vtkSmartPointer<vtkRenderWindow> renderWindow =
    vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer( renderer );

    vtkSmartPointer<vtkRenderWindowInteractor> renWinInteractor =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renWinInteractor->SetRenderWindow( renderWindow );

    renderWindow->Render();
    renWinInteractor->Start();
    return EXIT_SUCCESS;
}

Output:

signedDistance: 0.525072
closetPoint: PointStruct [0.974928, 0, 0]
absDis: 0.570277

If the input data for vtkImplicitPolyDataDistance object is a curve, we can compute every distance from the target point to the point on the curve and choose the minimum one as the final distance.

Categories: VTK

0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
A prohibited operation
0
Would love your thoughts, please comment.x
()
x