The algorithm vtkOBBTree::ComputeOBB can help us to calculate the three axes defining the orientation of the OBB(oriented bounding box). It is very useful for us to get the model’s spatial features.

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkLight.h>
#include <vtkCamera.h>
#include <vtkOBBTree.h>
#include <vtkActor2D.h>
#include <stdio.h>
#include <vtkLineSource.h>
#include <vtkPolyDataMapper.h>
#include "tool.h"
#include <vtkSTLReader.h>
using namespace std;

#define vSP vtkSmartPointer
#define vSPNew(Var, Type) vSP<Type> Var = vSP<Type>::New();

int main()
{
    setbuf( stdout, nullptr );

    vSPNew( reader, vtkSTLReader );
    reader->SetFileName( "~/Desktop/arch_u.stl" );
    reader->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData( reader->GetOutput() );

    vtkSmartPointer<vtkActor> actor =
            vtkSmartPointer<vtkActor>::New();
    actor->SetMapper( mapper );

    vtkSmartPointer<vtkRenderer> renderer =
            vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(actor);
    renderer->SetBackground( 0, 0, 0 );

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

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

    renderer->ResetCamera();

    PointStruct corner, max, mid, min, size;
    PointStruct realSize;
    vSPNew( obbTree, vtkOBBTree );
    obbTree->ComputeOBB( reader->GetOutput(), corner.point, max.point, mid.point, min.point, size.point );
    cout << "corner: (" << corner[0] << ", " << corner[1] << ", " << corner[2] << ")\n";
    cout << "max: (" << max[0] << ", " << max[1] << ", " << max[2] << ")\n";
    cout << "mid: (" << mid[0] << ", " << mid[1] << ", " << mid[2] << ")\n";
    cout << "min: (" << min[0] << ", " << min[1] << ", " << min[2] << ")\n";
    cout << "size: (" << size[0] << ", " << size[1] << ", " << size[2] << ")\n";
    realSize[0] = max.Length();
    realSize[1] = mid.Length();
    realSize[2] = min.Length();
    max.Unit();
    mid.Unit();
    min.Unit();
    cout << "max: (" << max[0] << ", " << max[1] << ", " << max[2] << ")\n";
    cout << "mid: (" << mid[0] << ", " << mid[1] << ", " << mid[2] << ")\n";
    cout << "min: (" << min[0] << ", " << min[1] << ", " << min[2] << ")\n";

    PointStruct tmp2(corner + max*size[0]);
    vSPNew( line1, vtkLineSource );
    line1->SetPoint1( corner.point );
    line1->SetPoint2( (corner + max*realSize[0]).point );
    cout << "corner1: " << corner;
    cout << "corner2: " << tmp2;
    line1->Update();
    vSPNew( mapper1, vtkPolyDataMapper );
    mapper1->SetInputData( line1->GetOutput() );
    vSPNew( actor1, vtkActor );
    actor1->SetMapper( mapper1 );
    actor1->GetProperty()->SetColor( 1, 0, 0 );
    actor1->GetProperty()->SetLineWidth(1);
    renderer->AddActor( actor1 );

    vSPNew( line2, vtkLineSource );
    line2->SetPoint1( corner.point );
    line2->SetPoint2( (corner + mid*realSize[1]).point );
    line2->Update();
    vSPNew( mapper2, vtkPolyDataMapper );
    mapper2->SetInputData( line2->GetOutput() );
    vSPNew( actor2, vtkActor );
    actor2->SetMapper( mapper2 );
    actor2->GetProperty()->SetColor( 0, 1, 0 );
    actor2->GetProperty()->SetLineWidth(1);
    renderer->AddActor( actor2 );

    vSPNew( line3, vtkLineSource );
    line3->SetPoint1( corner.point );
    line3->SetPoint2( (corner + min*realSize[2]).point );
    line3->Update();
    vSPNew( mapper3, vtkPolyDataMapper );
    mapper3->SetInputData( line3->GetOutput() );
    vSPNew( actor3, vtkActor );
    actor3->SetMapper( mapper3 );
    actor3->GetProperty()->SetColor( 0, 0, 1 );
    actor3->GetProperty()->SetLineWidth(1);
    renderer->AddActor( actor3 );

    renderWindow->Render();
    renderWindowInteractor->Start();
    return 0;
}

Output for Upper arch:

corner: (-39.4753, -5.01287, 25.2395)
max: (75.0509, -0.322946, 5.87045)
mid: (4.56893, 4.13678, -58.1839)
min: (-0.0429759, 34.3649, 2.43991)
size: (414.106, 288.631, 69.7376)
max: (0.996946, -0.00428989, 0.0779808)
mid: (0.0780887, 0.0707028, -0.994436)
min: (-0.00124743, 0.997488, 0.0708218)
corner1: PointStruct [-39.4753, -5.01287, 25.2395]
corner2: PointStruct [373.366, -6.78934, 57.5319]

If we rotate the original polydata, the OBB algorithm can also help us find correct axes.

    vSPNew( trans, vtkTransform );
    trans->RotateX( 90 );
    trans->Update();

    vSPNew( transformFilter, vtkTransformFilter );
    transformFilter->SetInputData( reader->GetOutput() );
    transformFilter->SetTransform( trans );
    transformFilter->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData( transformFilter->GetPolyDataOutput() );

Categories: VTK

1 Comment

Find The Biggest Plane On The Surface Of 3D Model | | theArcticOcean · 2020年4月28日 at pm10:13

[…] the arch to ignore other cells that normals are not equal to the min axes. You can read the article Explore The Orientation Of 3D Object about the min […]

Leave a Reply

Your email address will not be published. Required fields are marked *

You cannot copy content of this page