
# using tvtk seems to fail when reconstructing the cut surfacefor complicated boundaries.
# so i'm trying to write this with the clunkier vtk, but only using as much vtk as necessary

import vtk
from tvtk.api import colors

def SliceStl_tvtk( renderer, file, plane, color=colors.yellow, lineSize=4, opacity=1):
	"""using tvtk seems to fail when reconstructing the cut surfacefor complicated boundaries.

		Takes stl file and plane object
		cuts stl with plane
		returns the two pieces of the sliced stl"""
	from tvtk.api import tvtk
	from tvtk.api import colors
	#
	stl = tvtk.STLReader(file_name=file)
	stlNormals = tvtk.PolyDataNormals(input_connection=stl.output_port)
	#
	cutEdges = tvtk.Cutter(cut_function=plane, generate_cut_scalars=True,input_connection=stlNormals.output_port)  # Cuts the stl, creating lines where the function intersects the model.
	cutStrips = tvtk.Stripper(input_connection=cutEdges.output_port)  # Stripper then puts those lines together into polylines.
	cutStrips.update()
	cutPoly = tvtk.PolyData(points=cutStrips.output.points, polys=cutStrips.output.lines)
	#
	# Triangle filter is robust enough to ignore the duplicate point at
	# the beginning and end of the polygons and triangulate them.
	cutTriangles = tvtk.TriangleFilter()
	cutTriangles.set_input_data(cutPoly)
	cutMapper = tvtk.PolyDataMapper(input_connection=cutTriangles.output_port)
	cutMapper.set_input_data(cutPoly)
	cutProp = tvtk.Property(color=colors.yellow, edge_color=colors.green, edge_visibility=True)
	cutActor = tvtk.Actor(mapper=cutMapper, property=cutProp)
	#
	clipper = tvtk.ClipPolyData(input_connection=stlNormals.output_port, clip_function=plane, generate_clipped_output=True)#, generate_clip_scalars=True)
	#
	clipMapper = tvtk.PolyDataMapper(input_connection=clipper.output_port)
	clipProp = tvtk.Property(color=colors.peacock, opacity=0.3)
	clipActor = tvtk.Actor(mapper=clipMapper, property=clipProp)
	# renderer.add_actor(clipActor)
	#
	restMapper = tvtk.PolyDataMapper(input_connection=clipper.clipped_output_port)
	restProp = tvtk.Property(color=colors.yellow, opacity=0.7, edge_visibility=True)
	restActor = tvtk.Actor(mapper=restMapper, property=restProp)
	# renderer.add_actor(restActor)

	#
	# #   Join cut surface and rest surface to create a watertight stl
	#
	join = tvtk.AppendPolyData()
	join.add_input_data(clipper.output)
	join.add_input_data( cutTriangles.output )
	join.update()
	#  Remove any duplicate points.
	cleanFilter = tvtk.CleanPolyData(input_connection=join.output_port)
	cleanFilter.update()
	#
	joinMapper = tvtk.PolyDataMapper(input_connection=cleanFilter.output_port)
	joinProp = tvtk.Property(color=colors.green, opacity=1)
	joinActor = tvtk.Actor(mapper=joinMapper, property=joinProp)
	renderer.add_actor(joinActor)
	#
	# #   Write sliced output to stls
	#
	clipFile = file.replace('.stl', '_sliced.stl')
	writer = tvtk.STLWriter( input_connection=clipper.output_port, file_name=clipFile)
	writer.write()
	#
	restFile = file.replace('.stl', '_remain.stl')
	writer = tvtk.STLWriter( input_connection=clipper.clipped_output_port, file_name=restFile)
	writer.write()
	#
	cutFile = file.replace('.stl', '_cut.stl')
	writer = tvtk.STLWriter(input_connection=cutTriangles.output_port, file_name=cutFile)
	writer.write()
	#
	joinFile = file.replace('.stl', '_join.stl')
	writer = tvtk.STLWriter(input_connection=join.output_port, file_name=joinFile)
	writer.write()




# file = '/home/landisb/PycharmProjects/Data/cow.stl'
# origin = (0, 0, 1)
# normal = (-1, -1, 0)

file = '/home/landisb/PycharmProjects/PythonScripts/vtk/twoCylinders.stl'
origin=(0.25, 0.0, 10.0)
normal=(0.2, 0.1, 1)


# Create graphics renderer
ren = vtk.vtkRenderer()


# First start by reading a cow model. We also generate surface normals for prettier rendering.
stl = vtk.vtkSTLReader()
stl.SetFileName(file)
stlNormals = vtk.vtkPolyDataNormals()
stlNormals.SetInputConnection(stl.GetOutputPort())

# We clip with an implicit function. Here we use a plane positioned near the center of the cow model and oriented at an arbitrary angle.
plane = vtk.vtkPlane()
plane.SetOrigin(origin)
plane.SetNormal(normal)

# vtkClipPolyData requires an implicit function to define what it is to clip with.
# Any implicit function, including complex boolean combinations can be used.
# Notice that we can specify the value of the implicit function with the SetValue method.
clipper = vtk.vtkClipPolyData()
clipper.SetInputConnection(stlNormals.GetOutputPort())
clipper.SetClipFunction(plane)
clipper.GenerateClippedOutputOn()

clipMapper = vtk.vtkPolyDataMapper()
clipMapper.SetInputConnection(clipper.GetOutputPort())
clipMapper.ScalarVisibilityOff()

backProp = vtk.vtkProperty()
backProp.SetDiffuseColor(colors.tomato)

clipActor = vtk.vtkActor()
clipActor.SetMapper(clipMapper)
clipActor.GetProperty().SetColor(colors.peacock)
clipActor.SetBackfaceProperty(backProp)

# Here we are cutting the cow.
# Cutting creates lines where the cut function intersects the model.
# (Clipping removes a portion of the model but the dimension of the data does not change.)
# The reason we are cutting is to generate a closed polygon at the boundary of the clipping process.
#
# The cutter generates line segments.
cutEdges = vtk.vtkCutter()
cutEdges.SetInputConnection(stlNormals.GetOutputPort())
cutEdges.SetCutFunction(plane)
cutEdges.GenerateCutScalarsOn()
# The stripper then puts them together into polylines.
cutStrips = vtk.vtkStripper()
cutStrips.SetInputConnection(cutEdges.GetOutputPort())
cutStrips.Update()

######################################

import numpy as np

gmshFile = file.replace('.stl', '_vtk.geo')
print gmshFile
gmsh = open(gmshFile, 'w')

points = cutStrips.GetOutput().GetPoints()
pNum = points.GetNumberOfPoints()
for p in xrange(pNum):
	point = points.GetPoint(p)
	gmsh.write('Point ({}) = {{ {}, {}, {} }};\n'.format(p, *point))


lines = cutStrips.GetOutput().GetLines()

help(vtk.vtkCellArray)
# raw_input('...')
print lines

idList = vtk.vtkIdList()
lines.GetCell(0,idList)
actualIdList = []
for i in range( idList.GetNumberOfIds() ):
	id = idList.GetId(i)
	actualIdList.append(int(id))
for i in xrange( len(actualIdList) - 1):
	gmsh.write('Line ({}) = {{ {}, {} }};\n'.format(i+1, actualIdList[i], actualIdList[i + 1]))

print idList

firstNum = len(actualIdList)
also = i
print firstNum, i

lines.GetCell(1,idList)

print idList
actualIdList = []
for i in range( idList.GetNumberOfIds() ):
	id = idList.GetId(i)
	actualIdList.append(int(id))
for i in xrange( len(actualIdList) - 1):
	gmsh.write('Line ({}) = {{ {}, {} }};\n'.format(i+firstNum, actualIdList[i], actualIdList[i + 1]))



gmsh.close()

# raw_input('...')

######################################

# We then pull a trick and define polygons using the closed line segements that the stripper created.
cutPoly = vtk.vtkPolyData()
cutPoly.SetPoints(cutStrips.GetOutput().GetPoints())
cutPoly.SetPolys(cutStrips.GetOutput().GetLines())

# Drawing the boundary ie cutStrips
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cutStrips.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(colors.green)
actor.GetProperty().SetLineWidth(5)


# Triangle filter is robust enough to ignore the duplicate point at
# the beginning and end of the polygons and triangulate them.
cutTriangles = vtk.vtkTriangleFilter()
cutTriangles.SetInputData(cutPoly)
cutMapper = vtk.vtkPolyDataMapper()
cutMapper.SetInputData(cutPoly)
cutMapper.SetInputConnection(cutTriangles.GetOutputPort())
cutActor = vtk.vtkActor()
cutActor.SetMapper(cutMapper)
cutActor.GetProperty().SetColor(colors.yellow)
#Added
cutActor.GetProperty().SetEdgeVisibility(True)
cutActor.GetProperty().SetEdgeColor(colors.black)

###########################################################
cutFile = file.replace('.stl', '_cut.stl')

# Guessing how to write to an stl in vtk

# writer = tvtk.STLWriter(input_connection=cutTriangles.output_port, file_name=cutFile)
# writer.write()
writer = vtk.vtkSTLWriter()
writer.SetInputConnection(cutTriangles.GetOutputPort() )
writer.SetFileName(cutFile)
writer.SetFileTypeToBinary()
writer.Write()
print 'Wrote', cutFile
# Create the rest graphics stuff
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)

# Add the actors to the renderer, set the background and size
ren.AddActor(clipActor)
ren.AddActor(cutActor)
# ren.AddActor(restActor)
ren.AddActor(actor)
ren.SetBackground(1, 1, 1)
ren.ResetCamera()
ren.GetActiveCamera().Azimuth(30)
ren.GetActiveCamera().Elevation(30)
ren.GetActiveCamera().Dolly(1.5)
ren.ResetCameraClippingRange()

renWin.SetSize(300, 300)
iren.Initialize()

renWin.Render()
iren.Start()