require "vtk/Gtk"
require "numru/gphys"



###
# Now actually create the GUI
Gtk.init
Gtk::GL.init
root = Gtk::Window.new(Gtk::Window::TOPLEVEL)
top = Gtk::VBox.new
root.add(top)
@renWin = GtkGLExtVTKRenderWindow.new
top.pack_start(@renWin)


# Start by loading some data.
if ARGV.length==1
  gphys = NumRu::GPhys::IO.open_gturl(ARGV[0])
elsif ARGV.length==2
  fname,vname = ARGV[0..1]
  gphys = NumRu::GPhys::IO.open(fname,vname)
else
  raise "Usage: ruby #$0 filename varname"
end
gphys.rank<3 && raise("data must have at least 3 dimensions")
ind = Array.new(gphys.rank,0)
ind[0] = true
ind[1] = true
ind[2] = true
gphys = gphys[*ind]
shape = gphys.shape
min = gphys.min.val
max = gphys.max.val
#data = (gphys.val-min)/(max-min)
data = gphys.val
NArrayMiss===data && data = data.get_array


x = gphys.coord(0).val
xwid = x.max-x.min
y = gphys.coord(1).val
ywid = y.max-y.min
z = gphys.coord(2).val
zwid = z.max-z.min

yfact = xwid/ywid
zfact = xwid/zwid


grid = Vtk::RectilinearGrid.new
grid.SetDimensions(*shape)
grid.SetXCoordinates(x.to_va)
grid.SetYCoordinates(y.to_va)
grid.SetZCoordinates(z.to_va)
grid.GetPointData.SetScalars(data.reshape!(shape[0]*shape[1]*shape[2]).to_va)




# An outline is shown for context.
outline = Vtk::OutlineFilter.new
outline.SetInput(grid)

outlineMapper = Vtk::PolyDataMapper.new
outlineMapper.SetInput(outline.GetOutput())

outlineActor = Vtk::Actor.new
outlineActor.SetMapper(outlineMapper)
outlineActor.SetScale(1,yfact,zfact)

# Isosurface
@surface = Vtk::ContourFilter.new
@surface.SetInput(grid)
@surface.SetValue(0,(max+min)/2)
#normal = Vtk::PolyDataNormals.new
#normal.SetInput(@surface.GetOutput)
#normal.SetFeatureAngle(45)
mapper = Vtk::PolyDataMapper.new
mapper.SetInput(@surface.GetOutput)
#mapper.SetInput(normal.GetOutput)
mapper.SetScalarModeToUsePointFieldData
actor = Vtk::Actor.new
actor.SetMapper(mapper)
actor.GetProperty.SetOpacity(0.5)
actor.SetScale(1,yfact,zfact)



# Create the RenderWindow and Renderer
@ren = Vtk::Renderer.new
@renWin.GetRenderWindow.AddRenderer(@ren)

# Add the outline actor to the renderer, set the background color and size
@ren.AddActor(outlineActor)
@ren.AddActor(actor)
@renWin.set_size_request(500, 500)
@ren.SetBackground(0.1, 0.1, 0.2)

=begin
tprop = Vtk::TextProperty.new
tprop.SetColor(1,1,1)
axes = Vtk::CubeAxesActor2D.new
axes.SetInput(grid)
axes.SetCamera(@ren.GetActiveCamera)
#axes.SetLabelFormat("%4.2f")
#axes.SetFlyModeToOuterEdges
#axes.SetFlyModeToClosestTriad
axes.SetFontFactor(1.2)
axes.SetAxisTitleTextProperty(tprop)
axes.SetAxisLabelTextProperty(tprop)
axes.UseRangesOn
axes.ScalingOff
@ren.AddProp(axes)
=end

# Create the GUI
# We first create the supporting functions (callbacks) for the GUI

# Capture the display and place in a PNG
def captureImage()
  w2i = Vtk::WindowToImageFilter.new
  writer = Vtk::PNGWriter.new
  w2i.SetInput(@renWin.GetRenderWindow)
  w2i.Update()
  writer.SetInput(w2i.GetOutput())
  writer.SetFileName("image.png")
  @renWin.Render()
  writer.Write()
end
 

        
def SetSlice(adj)
  @surface.SetValue(0,adj.value)
  @ren.ResetCameraClippingRange()
  @renWin.Render()
end




# Buttons
ctrl_buttons = Gtk::HBox.new

quit_button = Gtk::Button.new("Quit")
quit_button.signal_connect("clicked"){ Gtk.main_quit }
capture_button = Gtk::Button.new("PNG")
capture_button.signal_connect("clicked"){ captureImage }
ctrl_buttons.pack_start(quit_button)
ctrl_buttons.pack_start(capture_button)
top.pack_start(ctrl_buttons)



# Add a slice scale to browse the current slice stack

slice = Gtk::HScale.new(min,max,(max-min)/100)
slice.value = (max+min)/2
@adjust = slice.adjustment
@adjust.signal_connect("value-changed"){|w| SetSlice(w) }
top.pack_start(slice)

# Done with the GUI. 
###


# Create an initial interesting view
cam1 = @ren.GetActiveCamera()
cam1.Elevation(-60)
cam1.SetViewUp(0, 0, 1)
cam1.Azimuth(30)
@ren.ResetCameraClippingRange()



# Start Tkinter event loop
root.show_all
Gtk.main
