# This script demonstrates an anomaly in color mapping using
# vtkMapper::InterpolateScalarsBeforeMapping with a small number
# of colors in the table.

import vtk

#
nx=51
Xmin=0.0
Xmax=5.0
Ymin=0.0
Ymax=1.0
Vmin=0.13
Vmax=0.97
coords=list()
for j in range(0,2):
   for i in range(0,nx):
      x=Xmin + ((Xmax-Xmin)*i)/(nx-1)
      y=j
      z=0
      coords.append([x,y,z])
#
pts = vtk.vtkPoints()
values=vtk.vtkDoubleArray()
values.SetName('values')
for xyz in coords:
   pid=pts.InsertNextPoint(xyz[0],xyz[1],xyz[2])
   value= Vmin + ((Vmax-Vmin)*(xyz[0]-Xmin))/(Xmax-Xmin)
   values.InsertNextValue(value)
   #print("point {} : [{},{},{}] = {}".format(pid,xyz[0],xyz[1],xyz[2],value))
#
quads=vtk.vtkCellArray()
quad=vtk.vtkQuad()
for cid in range(0,nx-1):
   quads.InsertNextCell(4)
   p0 = cid
   pids = [ p0, p0+1, p0+nx+1, p0+nx ]
   for p in pids:
      quads.InsertCellPoint(p)
   #print("cell {} : [{}]".format(cid,pids))
#
poly = vtk.vtkPolyData()
poly.SetPoints(pts)
poly.GetPointData().AddArray(values)
poly.SetPolys(quads)
#
# The number of colors in the off-screen image is larger but the difference
# with the number of table values is not always the same.
lut = vtk.vtkLookupTable()
lut.SetNumberOfTableValues(4)
lut.SetRange(Vmin,Vmax)
#
# With vtkMapper::InterpolateScalarsBeforeMappingOn, the
# number of colors used in the off-screen-rendering is larger than
# the number of colors specified in the lookup table.
# With vtkMapper::InterpolateScalarsBeforeMappingOff, the
# number of colors used in the off-screen-rendering is OK
m = vtk.vtkPolyDataMapper()
m.SetInputData(poly)
m.SetScalarModeToUsePointFieldData()
m.SelectColorArray('values')
m.SetLookupTable(lut)
m.InterpolateScalarsBeforeMappingOn()
m.UseLookupTableScalarRangeOn()
#
a = vtk.vtkActor()
a.SetMapper(m)
#
r = vtk.vtkRenderer()
r.AddViewProp(a)
#
screenRW = vtk.vtkRenderWindow()
screenRW.SetSize(600,300)
#
fileRW = vtk.vtkRenderWindow()
fileRW.SetSize(600,300)
fileRW.OffScreenRenderingOn()
#
# On-screen rendering
def renderToScreen():
   screenRW.AddRenderer(r)
   print( "Rendering on screen ..." )
   screenRW.Render()
   screenRW.RemoveRenderer(r)
#
# Off-screen rendering
def renderToFile():
   fileRW.AddRenderer(r)
   fileRW.Render()
   #
   w2i = vtk.vtkWindowToImageFilter()
   w2i.SetInput( fileRW )
   #
   png = vtk.vtkPNGWriter()
   png.SetInputConnection(w2i.GetOutputPort())
   png.SetFileName(r'd:\vtk\colormap.png')
   print( "Rendering off screen ..." )
   png.Write()
   fileRW.RemoveRenderer(r)
#
# When rendering to screen the number of colors is OK,
# When rendering to file the number of colors is too large.
renderToScreen()
renderToFile()
