3D

두 물체 사이 최소 거리 구하기

반응형

두 물체 사이의 가시성 있는 삼각형만 포함한 최소 거리를 계산하려면 다음과 같은 주요 단계를 거쳐야 합니다:

  1. 각 물체에 대해 가시성 있는 삼각형을 찾습니다.
  2. 각 물체의 가시성 있는 삼각형의 각 점들 사이의 거리를 계산합니다.
  3. 이 중 가장 짧은 거리를 찾습니다.

아래는 이를 수행하는 C++ 코드 예제입니다. OpenMP를 사용하여 병렬 처리를 통해 가시성 테스트를 수행하며, 두 물체 사이의 최소 거리를 계산합니다.

 

#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkConeSource.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkCamera.h>
#include <vtkWindowToImageFilter.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkTriangle.h>
#include <vtkCell.h>
#include <vtkCellArray.h>
#include <vtkProperty.h>
#include <vtkXMLPolyDataWriter.h>
#include <omp.h>
#include <cmath>
#include <limits>
#include <set>
#include <vector>

// 함수: Z-buffer 가시성 확인
std::set<vtkIdType> GetVisibleTriangles(vtkSmartPointer<vtkRenderer> renderer, vtkSmartPointer<vtkRenderWindow> renderWindow, vtkSmartPointer<vtkPolyData> polyData, double cameraPosition[3])
{
    renderer->GetActiveCamera()->SetPosition(cameraPosition);
    renderer->ResetCamera();
    renderWindow->Render();

    vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
    windowToImageFilter->SetInput(renderWindow);
    windowToImageFilter->SetInputBufferTypeToZBuffer();
    windowToImageFilter->Update();

    vtkSmartPointer<vtkImageData> zBuffer = windowToImageFilter->GetOutput();
    zBuffer->Update();

    std::set<vtkIdType> visibleTriangles;

    for (vtkIdType i = 0; i < polyData->GetNumberOfCells(); ++i)
    {
        vtkCell* cell = polyData->GetCell(i);
        if (cell->GetCellType() == VTK_TRIANGLE)
        {
            vtkPoints* points = cell->GetPoints();
            bool visible = false;
            for (vtkIdType j = 0; j < 3; ++j)
            {
                double point[3];
                points->GetPoint(j, point);
                double displayCoords[3];
                renderer->GetActiveCamera()->WorldToDisplay(point[0], point[1], point[2], displayCoords);
                int x = static_cast<int>(displayCoords[0]);
                int y = static_cast<int>(displayCoords[1]);
                if (x >= 0 && x < zBuffer->GetDimensions()[0] && y >= 0 && y < zBuffer->GetDimensions()[1])
                {
                    float zValue = zBuffer->GetScalarComponentAsFloat(x, y, 0);
                    if (zValue < displayCoords[2])
                    {
                        visible = true;
                        break;
                    }
                }
            }
            if (visible)
            {
                visibleTriangles.insert(i);
            }
        }
    }

    return visibleTriangles;
}

// 함수: 두 점 사이의 거리 계산
double Distance(const double p1[3], const double p2[3])
{
    return std::sqrt(std::pow(p1[0] - p2[0], 2) + std::pow(p1[1] - p2[1], 2) + std::pow(p1[2] - p2[2], 2));
}

// 함수: 두 물체 사이의 최소 거리 계산
double CalculateMinDistance(vtkSmartPointer<vtkPolyData> polyData1, const std::set<vtkIdType>& visibleTriangles1, vtkSmartPointer<vtkPolyData> polyData2, const std::set<vtkIdType>& visibleTriangles2)
{
    double minDistance = std::numeric_limits<double>::max();

    for (auto cellId1 : visibleTriangles1)
    {
        vtkCell* cell1 = polyData1->GetCell(cellId1);
        for (auto cellId2 : visibleTriangles2)
        {
            vtkCell* cell2 = polyData2->GetCell(cellId2);
            for (vtkIdType i = 0; i < 3; ++i)
            {
                double point1[3];
                cell1->GetPoints()->GetPoint(i, point1);
                for (vtkIdType j = 0; j < 3; ++j)
                {
                    double point2[3];
                    cell2->GetPoints()->GetPoint(j, point2);
                    double dist = Distance(point1, point2);
                    if (dist < minDistance)
                    {
                        minDistance = dist;
                    }
                }
            }
        }
    }

    return minDistance;
}

int main()
{
    // 예제 데이터 생성: 구체와 원뿔
    vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->Update();
    vtkSmartPointer<vtkPolyData> spherePolyData = sphereSource->GetOutput();

    vtkSmartPointer<vtkConeSource> coneSource = vtkSmartPointer<vtkConeSource>::New();
    coneSource->SetCenter(2.0, 0.0, 0.0); // 구체와 원뿔을 분리하여 배치
    coneSource->Update();
    vtkSmartPointer<vtkPolyData> conePolyData = coneSource->GetOutput();

    // 렌더러 및 렌더 윈도우 설정
    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
    vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(renderer);

    // 폴리데이터 매퍼 및 액터 설정 (구체)
    vtkSmartPointer<vtkPolyDataMapper> sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    sphereMapper->SetInputData(spherePolyData);
    vtkSmartPointer<vtkActor> sphereActor = vtkSmartPointer<vtkActor>::New();
    sphereActor->SetMapper(sphereMapper);
    renderer->AddActor(sphereActor);

    // 폴리데이터 매퍼 및 액터 설정 (원뿔)
    vtkSmartPointer<vtkPolyDataMapper> coneMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    coneMapper->SetInputData(conePolyData);
    vtkSmartPointer<vtkActor> coneActor = vtkSmartPointer<vtkActor>::New();
    coneActor->SetMapper(coneMapper);
    renderer->AddActor(coneActor);

    // 다양한 카메라 위치 설정
    std::vector<double[3]> cameraPositions = {
        {1, 0, 0}, {-1, 0, 0},
        {0, 1, 0}, {0, -1, 0},
        {0, 0, 1}, {0, 0, -1}
    };

    // 병렬 처리로 모든 방향에서 구체의 가시성 확인
    std::set<vtkIdType> visibleTrianglesSphere;
    #pragma omp parallel
    {
        std::set<vtkIdType> localVisibleTrianglesSphere;
        #pragma omp for nowait
        for (size_t i = 0; i < cameraPositions.size(); ++i)
        {
            // 원뿔을 비활성화하고 구체의 가시성만 확인
            coneActor->SetVisibility(0);
            auto visibleTriangles = GetVisibleTriangles(renderer, renderWindow, spherePolyData, cameraPositions[i]);
            #pragma omp critical
            visibleTrianglesSphere.insert(visibleTriangles.begin(), visibleTriangles.end());
            coneActor->SetVisibility(1); // 다시 활성화
        }
    }

    // 병렬 처리로 모든 방향에서 원뿔의 가시성 확인
    std::set<vtkIdType> visibleTrianglesCone;
    #pragma omp parallel
    {
        std::set<vtkIdType> localVisibleTrianglesCone;
        #pragma omp for nowait
        for (size_t i = 0; i < cameraPositions.size(); ++i)
        {
            // 구체를 비활성화하고 원뿔의 가시성만 확인
            sphereActor->SetVisibility(0);
            auto visibleTriangles = GetVisibleTriangles(renderer, renderWindow, conePolyData, cameraPositions[i]);
            #pragma omp critical
            visibleTrianglesCone.insert(visibleTriangles.begin(), visibleTriangles.end());
            sphereActor->SetVisibility(1); // 다시 활성화
        }
    }

    // 두 물체 사이의 최소 거리 계산
    double minDistance = CalculateMinDistance(spherePolyData, visibleTrianglesSphere, conePolyData, visibleTrianglesCone);
    std::cout << "Minimum distance between visible triangles of the two objects: " << minDistance << std::endl;

    // 결과 출력 (구체)
    vtkSmartPointer<vtkPolyDataMapper> resultMapperSphere = vtkSmartPointer<vtkPolyDataMapper>::New();
    resultMapperSphere->SetInputData(spherePolyData);
    vtkSmartPointer<vtkActor> resultActorSphere = vtkSmartPointer<vtkActor>::New();
    resultActorSphere->SetMapper(resultMapperSphere);
    renderer->AddActor(resultActorSphere);

    // 결과 출력 (원뿔)
    vtkSmartPointer<vtkPolyDataMapper> resultMapperCone = vtkSmartPointer<vtkPolyDataMapper>::New();
    resultMapperCone->SetInputData(conePolyData);
    vtkSmartPointer<vtkActor> resultActorCone = vtkSmartPointer<vtkActor>::New();
    resultActorCone->SetMapper(resultMapperCone);
    renderer->AddActor(resultActorCone);

    renderWindow->Render();
    renderWindow->Finalize();

    // 렌더 윈도우 인터랙터 설정 및 시작
    vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
    interactor->SetRenderWindow(renderWindow);
    renderWindow->Render();
    interactor->Start();

    return 0;
}

 

이 코드는 다음과 같은 주요 단계를 수행합니다:

  1. 두 개의 객체 (구체와 원뿔)를 생성합니다.
  2. vtkRenderer, vtkRenderWindow, 및 vtkRenderWindowInteractor를 설정합니다.
  3. 특정 객체 (구체)에 대해서만 가시성을 테스트하기 위해 다른 객체 (원뿔)를 비활성화하고, 병렬 처리를 사용하여 여러 카메라 위치에서 가시성을 확인합니다.
  4. 동일한 절차를 원뿔에 대해서도 수행합니다.
  5. 두 물체의 가시성 있는 삼각형 사이의 최소 거리를 계산합니다.
  6. 결과를 출력하고 화면에 렌더링합니다.

이 코드를 실행하면 두 물체의 가시성 있는 삼각형 사이의 최소 거리를 계산하여 출력합니다. 이 코드를 컴파일하고 실행하려면 VTK와 OpenMP를 지원하는 컴파일러가 필요하며, OpenMP를 사용하려면 컴파일 시 -fopenmp 플래그를 추가해야 합니다.

반응형