#  Copyright (c) 1997-2010
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
#  http://www.polymake.de
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------
#  $Project: polymake $$Id: visual.rules 9564 2010-03-14 19:43:08Z herr $

package Visual::Color;

# graph edges: black
custom $graph="0 0 0";

require Visual::Graph;
require Visual::Lattice;

###############################################################################
#
# Home-made 3-d spring embedder with variations
#
package Visual::GraphEmbedding;

# Tuning parameters for the graph embedder.
# Almost all are multiplicative factors; the comments describe
# the effect of INCREASING of the corresponding parameter.
custom %graph_parameters=(
# scale => 1,           # the average edge length increases	
  inertion => 0.1,      # the computations might converge more slowly, but more steadily
 viscosity => 1,       # improves the convergence at the risk of being stuck at a bad local minimum
# 'max-iterations' => 10000,  # The iteration limit. Not multiplicative!
  balance => 10,        # the non-neighbor nodes are more spread away from each other
);

# Additional tuning parameters for the interactive spring embedder.
custom %interactive_parameters=(
  'eps' => 1e-4         # the movement to be accepted as "no movement"
);

@ISA=qw( Visual::Interactive );

# perform static computations
sub compute {
   my ($self)=@_;
   $self->merge_options(\%graph_parameters);
   spring_embedder($self->source, $self->options);
}

# run interactive embedder
sub run {
   my ($self)=@_;
   $self->merge_options(\%graph_parameters);
   $self->merge_options(\%interactive_parameters);
   $self->coord=[ 0..$self->source->nodes-1 ];
   $self->client_object=interactive_spring_embedder($self->source, $self->options);
   return $self->client_object->port;
}

sub cols { 3 }

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

package Visual::HDEmbedding;

use Polymake::Struct (
   [ '@ISA' => 'Interactive' ],
   '@label_width',
);

sub compute {
   my ($self)=@_;
   hd_embedder($self->source, $self->label_width, $self->options);
}

sub cols { 2 }

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

package application;

# Graph object, { optional parameters } => Visual::GraphEmbedding
function spring_embedding_3d {
   new Visual::GraphEmbedding(@_);
}

# FaceLattice object, { optional parameters } => Visual::HDEmbedding
function hd_embedding {
   new Visual::HDEmbedding(@_);
}

function enforce_static(Visual::Graph) {
   enforce_static_coord($_[0], "Vertices");
}

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

object Graph {

# @category Visualization
# Visualizes the graph.
# Decorations may include ''Coord'', disabling the default spring embedder.
# @option Int seed random seed value for the spring embedder
# @return Visual::Graph

user_method VISUAL(%Visual::Graph::decorations, { seed => undef }) : ADJACENCY {
   my ($this, $decor, $seed)=@_;
   visualize( new Visual::Graph( Name => $this->name,
				 Adjacency => $this->ADJACENCY,
				 NodeLabels => $this->lookup("NODE_LABELS"),
				 exists($decor->{Coord}) ? () :
				 ( Coord => spring_embedding_3d($this->ADJACENCY->has_gaps ? renumber_nodes($this->ADJACENCY) : $this->ADJACENCY, $seed) ),
				 $decor,
			       ));
}

}

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

object FaceLattice {

# @category Visualization
# Visualize the FaceLattice.
# @option Int seed random seed value for the node placement
# @return Visual::Lattice

user_method VISUAL(%Visual::Lattice::decorations, { seed => undef }) {
   my ($this, $decor, $seed)=@_;
   my $top_node=$this->top_node;
   my $VL=new Visual::Lattice( Name => $this->name,
			       Adjacency => $this->ADJACENCY,
			       Faces => $this->FACES,
			       top_node => $top_node,
			       ArrowStyle => 0,
			       NodeBorderColor => "black",
			       Coord => hd_embedding($this,$seed),
			       $decor
			     );
   my $black_top_node=sub { $_[0]==$top_node ? "0 0 0" : undef };
   $VL->merge(NodeColor => $black_top_node);
   if (exists $decor->{NodeBorderColor}) { $VL->merge(NodeBorderColor => $black_top_node); }
   visualize($VL);
}

# @category Visualization
# Visualize the dual FaceLattice.
# @option Int seed random seed value for the node placement
# @return Visual::Lattice
user_method VISUAL_DUAL(%Visual::Lattice::decorations, { seed => undef }) {
   my ($this, $decor, $seed)=@_;
   my $top_node=$this->top_node;
   my $VL=new Visual::Lattice( Name => "Dual to ".$this->name,
			       Adjacency => $this->ADJACENCY,
			       Faces => $this->dual_faces,
			       Mode => "dual",
			       top_node => $top_node,
			       ArrowStyle => 0,
			       NodeBorderColor => "black",
			       Coord => hd_embedding($this,$seed),
			       $decor
			     );
   my $black_top_node=sub { $_[0]==$top_node ? "0 0 0" : undef };
   $VL->merge(NodeColor => $black_top_node);
   if (exists $decor->{NodeBorderColor}) { $VL->merge(NodeBorderColor => $black_top_node); }
   visualize($VL);
}

}

# @category Visualization
# Write a graph in LEDA input format.
user_function LEDA_graph(props::Graph $) {
   my ($G, $out)=@_;
   my $n=$G->nodes;
   print $out <<".", ("|{}|\n")x$n, $G->edges, "\n";
LEDA.GRAPH


$n
.
   for (my $e=entire(edges($G)); $e; ++$e) {
      print $out $e->from_node, " ", $e->to_node, " 0 |{}|\n";
   }
}

# Local Variables:
# mode: perl
# c-basic-offset:3
# End:
