#!/usr/bin/env python

# Demonstrate computation of volumes and areas of objects
# defined by polygonal meshes
from vtkmodules.vtkCommonCore import vtkPoints
from vtkmodules.vtkCommonDataModel import (
    vtkCellArray,
    vtkPolyData,
)
from vtkmodules.vtkFiltersCore import vtkMultiObjectMassProperties
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer,
)
import vtkmodules.vtkInteractionStyle
import vtkmodules.vtkRenderingFreeType
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.util.misc import vtkGetDataRoot

VTK_DATA_ROOT = vtkGetDataRoot()

# Create the RenderWindow, Renderer
#
ren = vtkRenderer()
renWin = vtkRenderWindow()
renWin.AddRenderer(ren)

iren = vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)

# Create "blocks" out of combinations of polygons, with
# different orientations, each with total volume of 1
# and total area of 6. Additionally, a non-manifold
# polygonal "mess" tests the invalid state.
polyData = vtkPolyData()
pts = vtkPoints()
polys = vtkCellArray()
polyData.SetPoints(pts)
polyData.SetPolys(polys)

pts.SetNumberOfPoints(42)
# First block
pts.SetPoint(0, -2, -2, -0.5)
pts.SetPoint(1, -1, -2, -0.5)
pts.SetPoint(2, -2, -1, -0.5)
pts.SetPoint(3, -1, -1, -0.5)
pts.SetPoint(4, -2, -2, 0.5)
pts.SetPoint(5, -1, -2, 0.5)
pts.SetPoint(6, -2, -1, 0.5)
pts.SetPoint(7, -1, -1, 0.5)

# Second block
pts.SetPoint(8, 1, -2, -0.5)
pts.SetPoint(9, 2, -2, -0.5)
pts.SetPoint(10, 1, -1, -0.5)
pts.SetPoint(11, 2, -1, -0.5)
pts.SetPoint(12, 1, -2, 0.5)
pts.SetPoint(13, 2, -2, 0.5)
pts.SetPoint(14, 1, -1, 0.5)
pts.SetPoint(15, 2, -1, 0.5)

# Third block
pts.SetPoint(16, -2, 1, -0.5)
pts.SetPoint(17, -1, 1, -0.5)
pts.SetPoint(18, -2, 2, -0.5)
pts.SetPoint(19, -1, 2, -0.5)
pts.SetPoint(20, -2, 1, 0.5)
pts.SetPoint(21, -1, 1, 0.5)
pts.SetPoint(22, -2, 2, 0.5)
pts.SetPoint(23, -1, 2, 0.5)

# Fourth block
pts.SetPoint(24, 1, 1, -0.5)
pts.SetPoint(25, 2, 1, -0.5)
pts.SetPoint(26, 1, 2, -0.5)
pts.SetPoint(27, 2, 2, -0.5)
pts.SetPoint(28, 1, 1, 0.5)
pts.SetPoint(29, 2, 1, 0.5)
pts.SetPoint(30, 1, 2, 0.5)
pts.SetPoint(31, 2, 2, 0.5)

# Invalid poly mess (a "X")
pts.SetPoint(32, 0, -0.5, -0.5)
pts.SetPoint(33, 0, 0.5, -0.5)
pts.SetPoint(34, -0.5, -0.5, 0)
pts.SetPoint(35, 0, -0.5, 0)
pts.SetPoint(36, 0.5, -0.5, 0)
pts.SetPoint(37, -0.5, 0.5, 0)
pts.SetPoint(38, 0, 0.5, 0)
pts.SetPoint(39, 0.5, 0.5, 0)
pts.SetPoint(40, 0, -0.5, 0.5)
pts.SetPoint(41, 0, 0.5, 0.5)

# First block - all quads, consistent order
polys.InsertNextCell(4)
polys.InsertCellPoint(0)
polys.InsertCellPoint(1)
polys.InsertCellPoint(3)
polys.InsertCellPoint(2)

polys.InsertNextCell(4)
polys.InsertCellPoint(4)
polys.InsertCellPoint(6)
polys.InsertCellPoint(7)
polys.InsertCellPoint(5)

polys.InsertNextCell(4)
polys.InsertCellPoint(0)
polys.InsertCellPoint(4)
polys.InsertCellPoint(5)
polys.InsertCellPoint(1)

polys.InsertNextCell(4)
polys.InsertCellPoint(3)
polys.InsertCellPoint(7)
polys.InsertCellPoint(6)
polys.InsertCellPoint(2)

polys.InsertNextCell(4)
polys.InsertCellPoint(1)
polys.InsertCellPoint(5)
polys.InsertCellPoint(7)
polys.InsertCellPoint(3)

polys.InsertNextCell(4)
polys.InsertCellPoint(2)
polys.InsertCellPoint(6)
polys.InsertCellPoint(4)
polys.InsertCellPoint(0)

# Second block - quads with a reversed polygon
polys.InsertNextCell(4)
polys.InsertCellPoint(8)
polys.InsertCellPoint(9)
polys.InsertCellPoint(11)
polys.InsertCellPoint(10)

polys.InsertNextCell(4)
polys.InsertCellPoint(12)
polys.InsertCellPoint(13)
polys.InsertCellPoint(15)
polys.InsertCellPoint(14)

polys.InsertNextCell(4)
polys.InsertCellPoint(8)
polys.InsertCellPoint(12)
polys.InsertCellPoint(13)
polys.InsertCellPoint(9)

polys.InsertNextCell(4)
polys.InsertCellPoint(11)
polys.InsertCellPoint(15)
polys.InsertCellPoint(14)
polys.InsertCellPoint(10)

polys.InsertNextCell(4)
polys.InsertCellPoint(9)
polys.InsertCellPoint(13)
polys.InsertCellPoint(15)
polys.InsertCellPoint(11)

polys.InsertNextCell(4)
polys.InsertCellPoint(10)
polys.InsertCellPoint(14)
polys.InsertCellPoint(12)
polys.InsertCellPoint(8)

# Third block - with triangles + quads
polys.InsertNextCell(3)
polys.InsertCellPoint(16)
polys.InsertCellPoint(17)
polys.InsertCellPoint(19)

polys.InsertNextCell(3)
polys.InsertCellPoint(19)
polys.InsertCellPoint(18)
polys.InsertCellPoint(16)

polys.InsertNextCell(4)
polys.InsertCellPoint(20)
polys.InsertCellPoint(22)
polys.InsertCellPoint(23)
polys.InsertCellPoint(21)

polys.InsertNextCell(4)
polys.InsertCellPoint(16)
polys.InsertCellPoint(20)
polys.InsertCellPoint(21)
polys.InsertCellPoint(17)

polys.InsertNextCell(4)
polys.InsertCellPoint(19)
polys.InsertCellPoint(23)
polys.InsertCellPoint(22)
polys.InsertCellPoint(18)

polys.InsertNextCell(4)
polys.InsertCellPoint(17)
polys.InsertCellPoint(21)
polys.InsertCellPoint(23)
polys.InsertCellPoint(19)

polys.InsertNextCell(4)
polys.InsertCellPoint(18)
polys.InsertCellPoint(22)
polys.InsertCellPoint(20)
polys.InsertCellPoint(16)

# Fourth block - with triangles + quads + reversals
polys.InsertNextCell(3)
polys.InsertCellPoint(24)
polys.InsertCellPoint(25)
polys.InsertCellPoint(27)

polys.InsertNextCell(3)
polys.InsertCellPoint(26)
polys.InsertCellPoint(27)
polys.InsertCellPoint(24)

polys.InsertNextCell(4)
polys.InsertCellPoint(28)
polys.InsertCellPoint(30)
polys.InsertCellPoint(31)
polys.InsertCellPoint(29)

polys.InsertNextCell(4)
polys.InsertCellPoint(24)
polys.InsertCellPoint(28)
polys.InsertCellPoint(29)
polys.InsertCellPoint(25)

polys.InsertNextCell(4)
polys.InsertCellPoint(27)
polys.InsertCellPoint(31)
polys.InsertCellPoint(30)
polys.InsertCellPoint(26)

polys.InsertNextCell(4)
polys.InsertCellPoint(25)
polys.InsertCellPoint(29)
polys.InsertCellPoint(31)
polys.InsertCellPoint(27)

polys.InsertNextCell(4)
polys.InsertCellPoint(26)
polys.InsertCellPoint(30)
polys.InsertCellPoint(28)
polys.InsertCellPoint(24)

# Non-manifold Poly mess - four quads forming a "X"
polys.InsertNextCell(4)
polys.InsertCellPoint(32)
polys.InsertCellPoint(33)
polys.InsertCellPoint(38)
polys.InsertCellPoint(35)

polys.InsertNextCell(4)
polys.InsertCellPoint(34)
polys.InsertCellPoint(35)
polys.InsertCellPoint(38)
polys.InsertCellPoint(37)

polys.InsertNextCell(4)
polys.InsertCellPoint(35)
polys.InsertCellPoint(36)
polys.InsertCellPoint(39)
polys.InsertCellPoint(38)

polys.InsertNextCell(4)
polys.InsertCellPoint(35)
polys.InsertCellPoint(38)
polys.InsertCellPoint(41)
polys.InsertCellPoint(40)

# Compute volumes
massP = vtkMultiObjectMassProperties()
massP.SetInputData(polyData)
massP.Update()

print("Mass Properties: {0}".format(massP))
print("Number Objects: {0}".format(massP.GetNumberOfObjects()))
print("All Valid: {0}".format(massP.GetAllValid()))
print("Total Area: {0}".format(massP.GetTotalArea()))
print("Total Volume: {0}".format(massP.GetTotalVolume()))

numObjects = massP.GetNumberOfObjects()
validArray = massP.GetOutput().GetFieldData().GetArray("ObjectValidity")
areaArray = massP.GetOutput().GetFieldData().GetArray("ObjectAreas")
volArray = massP.GetOutput().GetFieldData().GetArray("ObjectVolumes")
centroidArray = massP.GetOutput().GetFieldData().GetArray("ObjectCentroids")
print("Object ID, Valid, Area, Volume, Centroid")
for i in range(0, numObjects):
    valid = validArray.GetTuple1(i)
    area = areaArray.GetTuple1(i)
    vol = volArray.GetTuple1(i)
    centroid = centroidArray.GetTuple3(i)
    print(i, valid, area, vol, centroid)

mapper = vtkPolyDataMapper()
mapper.SetInputConnection(massP.GetOutputPort())
mapper.ScalarVisibilityOff()

actor = vtkActor()
actor.SetMapper(mapper)

# Render it
ren.AddActor(actor)

ren.GetActiveCamera().SetPosition(0.5, 0.5, 1)
ren.GetActiveCamera().SetFocalPoint(0, 0, 0)
ren.ResetCamera()

renWin.Render()
iren.Start()
