# This example shows an attempt to display a solid surface with given holes, one hole

import vtkmodules.vtkInteractionStyle
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtk import vtkPoints
from vtk import vtkCellArray
from vtk import vtkPolyData
from vtk import vtkAppendPolyData
from vtk import vtkFeatureEdges
from vtk import vtkContourTriangulator
from vtk import vtkCleanPolyData
from vtk import vtkInteractorStyleTrackballCamera

from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)

import numpy as np

# Initialize renderer and window to be able to add actors and interact
ren1 = vtkRenderer();
colors = vtkNamedColors();
ren1.SetBackground(colors.GetColor3d("AliceBlue"));
renWin = vtkRenderWindow();
renWin.AddRenderer(ren1);
renWin.SetWindowName("py_standAlone_SurfaceWithHole");

# Preparing actors to be displayed on screen
def prepActors():
    # Define points for a surface with holes
    CornerPoints = np.array([[4.6680002212524414, 2.7000000476837158, 0.0000000000000000],
    [0.0000000000000000, 2.7000000476837158, 0.0000000000000000],
    [0.0000000000000000, 0.0000000000000000, 0.0000000000000000],
    [4.6680002212524414, 0.0000000000000000, 0.0000000000000000],
    [3.3680000305175781, 2.5299999713897705, 0.0000000000000000],
    [2.5179998874664307, 2.5299999713897705, 0.0000000000000000],
    [2.5179998874664307, 0.77999997138977051, 0.0000000000000000],
    [3.3680000305175781, 0.77999997138977051, 0.0000000000000000],
    [2.1159999370574951, 2.5299999713897705, 0.0000000000000000],
    [1.2660000324249268, 2.5299999713897705, 0.0000000000000000],
    [1.2660000324249268, 0.77999997138977051, 0.0000000000000000],
    [2.1159999370574951, 0.77999997138977051, 0.0000000000000000],
    [4.4450001716613770, 2.5480000972747803, 0.0000000000000000],
    [3.5950000286102295, 2.5480000972747803, 0.0000000000000000],
    [3.5950000286102295, 0.79799997806549072, 0.0000000000000000],
    [4.4450001716613770, 0.79799997806549072, 0.0000000000000000],
    [0.87000000476837158, 2.5299999713897705, 0.0000000000000000],
    [0.019999999552965164, 2.5299999713897705, 0.0000000000000000],
    [0.019999999552965164, 0.77999997138977051, 0.0000000000000000],
    [0.87000000476837158, 0.77999997138977051, 0.0000000000000000],
    [0.071999996900558472, 0.61199998855590820, 0.0000000000000000],
    [0.071999996900558472, 0.23999999463558197, 0.0000000000000000],
    [4.4450001716613770, 0.23999999463558197, 0.0000000000000000],
    [4.4450001716613770, 0.61199998855590820, 0.0000000000000000]])
    # Set-up points
    points = vtkPoints()
    for i in range(np.shape(CornerPoints)[0]):
        points.InsertNextPoint(CornerPoints[i,0], CornerPoints[i,1], CornerPoints[i,2]);
    # Create polydata to display the lines on screen
    polys = vtkCellArray();
    nCell = 4
    nPts = 4
    for i in range(6):
        polys.InsertNextCell(nCell);
        if i == 0:
            for j in range(nCell):
                polys.InsertCellPoint(j);
                print("%d "%j, end='')
        else:
            for j in range(nCell):
                polys.InsertCellPoint(nPts-j-1);
                print("%d "%(nPts-j-1), end='')
        print(" ")
        nPts = nPts+4
    lines = vtkCellArray();
    nPts = 4
    for i in range(6):
        for j in range(4*i,4*i+4):
            lines.InsertNextCell(2);
            lines.InsertCellPoint(j);
            lines.InsertCellPoint(4*i+(j+1)%4);            
            print("%d-%d "%(j,4*i+(j+1)%4), end='')
        print(" ")
        nPts = nPts+4
    polyData = vtkPolyData();
    polyData.SetPoints(points);
    polyData.SetPolys(polys);
    polyData.SetLines(lines);
    # Triangulate the shape vith vtkDelaunay2D filter
    tri = vtkContourTriangulator();
    tri.SetInputData(polyData);
    # Separate polydata for one of holes, which is then appended
    points = vtkPoints()
    for i in range(np.shape(CornerPoints)[0]-4, np.shape(CornerPoints)[0]):
        points.InsertNextPoint(CornerPoints[i,0], CornerPoints[i,1], CornerPoints[i,2]);
    polys = vtkCellArray();
    nCell = 4
    polys.InsertNextCell(nCell);
    for j in range(nCell):
        polys.InsertCellPoint(j);
        print("%d "%j, end='')
    print(" ")
    lines = vtkCellArray();
    for j in range(4):
        lines.InsertNextCell(2);
        lines.InsertCellPoint(j);
        lines.InsertCellPoint((j+1)%4);            
        print("%d-%d "%(j,(j+1)%4), end='')
    print(" ")
    polyData = vtkPolyData();
    polyData.SetPoints(points);
    polyData.SetPolys(polys);
    polyData.SetLines(lines);
    tri2 = vtkContourTriangulator();
    tri2.SetInputData(polyData);
    append = vtkAppendPolyData();
    append.AddInputConnection(tri.GetOutputPort())
    append.AddInputConnection(tri2.GetOutputPort())
    # Display the result on screen
    polyMapper = vtkPolyDataMapper();
    polyMapper.SetInputConnection(tri.GetOutputPort());
    actor = vtkActor();
    actor.SetMapper(polyMapper);
    actor.GetProperty().SetColor(0.8, 0.8, 0.8);
    actor.GetProperty().SetEdgeColor(0.8, 0.8, 0.8);
    actor.GetProperty().SetDiffuseColor(0.8, 0.8, 0.8);
    actor.GetProperty().SetSpecularColor(0.8, 0.8, 0.8);
    actor.GetProperty().SetAmbientColor(0.8, 0.8, 0.8);
    actor.GetProperty().SetRepresentationToWireframe();
    ren1.AddActor(actor);
    # Create feature edges of the surface
    edge = vtkFeatureEdges();
    edge.SetInputConnection(tri.GetOutputPort());
    edge.BoundaryEdgesOn();
    edge.ManifoldEdgesOff();
    edge.NonManifoldEdgesOff();
    edge.SetFeatureAngle(30);
    edge.ColoringOff();
    polyMapper = vtkPolyDataMapper();
    polyMapper.SetInputConnection(edge.GetOutputPort());
    actor = vtkActor();
    actor.SetMapper(polyMapper);
    actor.GetProperty().SetColor(0, 0, 0);
    actor.GetProperty().SetEdgeColor(0, 0, 0);
    actor.GetProperty().SetDiffuseColor(0, 0, 0);
    actor.GetProperty().SetSpecularColor(0, 0, 0);
    actor.GetProperty().SetAmbientColor(0, 0, 0);
    ren1.AddActor(actor);

def main():
    # Prepare actors
    prepActors();
    # Create interactor, add callback to show various results
    iren = vtkRenderWindowInteractor();
    iren.SetRenderWindow(renWin);
    iren.SetInteractorStyle(vtkInteractorStyleTrackballCamera());
    # Render and interact
    renWin.Render();
    ren1.GetActiveCamera().Elevation(15);
    ren1.GetActiveCamera().Azimuth(-55);
    iren.Start();

main()