# Copyright (c) 1997-2006 # Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany) # http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.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: schlegel.rules 7540 2006-12-21 21:04:18Z gawrilow $ object Polytope; # category: Visualization # Set of stored parameters to create a Schlegel diagram. # This is a temporary solution until the hierarchical objects are fully implemented. # property SCHLEGEL_PARAMS $type="text"; # A Schlegel diagram of a polytope object SchlegelDiagram # A reference to the polytope being visualized. # As soon as the object hierarchy is properly implemented, this property becomes the # regular 'parent' link. # property Polytope $type="object"; # The facet number in the original polytope, giving the projection plane. property FACET $type="cardinal"; $accept=sub : method { my ($this, $facet)=@_; if ($facet<0 || $facet>=$this->Polytope->N_FACETS) { die "facet index out of valid range 0..", $this->Polytope->N_FACETS-1, "\n"; } return $facet; }; # Zoom factor. property ZOOM $type="scalar"; $accept=sub { no integer; my $z=eval $_[0]; # FIXME: until Rational are directly available in perl die "zoom factor not in (0..1]\n" if $z<=0 || $z>1; return $_[0]; # return the original format }; # The intersection point of the projection facet and the view ray. property FACET_POINT $type="vector"; # The center point of the projection, lying outside the polytope. property VIEWPOINT $type="vector"; # A point on the view ray lying inside the polytope. property INNER_POINT $type="vector"; # Create the default set of parameters for the schlegel diagram FACET_POINT, INNER_POINT : Polytope, FACET ### Polytope.{VERTICES, VERTICES_IN_FACETS, VERTEX_BARYCENTER} client("schlegel_params", $this, $this->Polytope); # Matrix of a projective transformation mapping the whole polytope into the @see FACET # The points belonging to this facet stay fixed. property TRANSFORM $type="matrix"; # Coordinates in affine 3-space of the vertices which # correspond to a 3-dimensional (Schlegel-) projection of a 4-polytope. property VERTICES $type="matrix"; $temporary=1; TRANSFORM, VIEWPOINT : Polytope, FACET, ZOOM, FACET_POINT, INNER_POINT ### Polytope.{VERTICES, FACETS, DUAL_GRAPH} ### PRECONDITION: Polytope.BOUNDED ### $BOUNDED ### BODY: client("schlegel_transform", $this, $this->Polytope); method compute_vertices { my ($this, $result, @sections)=@_; client("schlegel_vertices", $this, $this->Polytope, $result, @sections); } VERTICES : Polytope, TRANSFORM, FACET ### Polytope.{VERTICES, FACETS} $this->compute_vertices("VERTICES", "VERTICES"); ################################################################################## # visualization package Visual::Schlegel; use Struct ( [ '@ISA' => 'Visual::Container' ], '$Schlegel', ); # the diagram itself as an embedded graph method basis_graph { $_[0]->elements->[0] } # Color of the Schlegel projection facet (RGB) custom $proj_facet="0 0 0"; # Color of the facets on the Schlegel projection (RGB) custom $solid_color="0 0 255"; # Illustrate the behavior of a linear objective function on the polytope. # Superpose the drawing with the directed graph induced by the objective function. user_method DIRECTED_GRAPH { my ($self)=@_; my $lp=$self->Schlegel->Polytope; $self->basis_graph->EdgeStyle="thickness 0.333"; push @{$self->elements}, new Visual::Graph( Name => "DIRECTED_GRAPH of " . $self->Schlegel->Polytope->name, Graph => $lp->DIRECTED_GRAPH, Coord => $self->basis_graph->Coord, NodeStyle => "hidden", Directed => 1, ); visualize($self); } # Illustrate the behavior of a linear objective function on the polytope. # Color the vertices according to the values of the objective function. user_method VERTEX_COLORS { my ($self)=@_; my $lp=$self->Schlegel->Polytope; $self->basis_graph->NodeColor=$lp->VERTEX_COLORS; visualize($self); } method append_points { my ($self, $points)=@_; my $G=$self->basis_graph; # important: $G->Coord remains magical! my $coord=$G->Coord; my $emb=detect_dynamic($coord); my $n=$emb->get_n_vertices; if ($emb==$G->Coord) { # no points besides own VERTICES so far $G->Coord=slice($G->Coord,0,$n-1); } $emb->push($points); return slice($G->Coord, $n, $n+@$points); } # Draw the edges of the @see Polytope.TRIANGULATION_BOUNDARY user_method TRIANGULATION_BOUNDARY { my ($self)=@_; my $P=$self->Schlegel->Polytope; $self->Name="Triangulation Boundary of ".$P->name; push @{$self->elements}, new Visual::Graph( Name => $P->name."-inner-edges", Graph => $P->TriangulationBoundaryInnerEdges($self->basis_graph), Coord => $self->basis_graph->Coord, NodeStyle => "hidden", EdgeStyle => "thickness 0.333", ); visualize($self); } user_method TRIANGULATION_BOUNDARY_SOLID(%Visual::Polyhedron::decorations) { my ($self, $decor)=@_; my $simplex_faces_3d=[ "{0 2 1}", "{0 1 3}", "{0 3 2}", "{1 2 3}" ]; my $G=$self->basis_graph; $G->VertexStyle = "hidden"; my $P=$self->Schlegel->Polytope; my $TB = $P->TRIANGULATION_BOUNDARY; my @triangulation; my $i = 0; foreach (@{$TB}) { my $facet = $_; $facet =~ s/^{(.*)}$/$1/; my @simplices = ($facet =~ m/{([\d\s]+)}/g); foreach my $simplex (@simplices) { my @points = ($simplex =~ /\d+/g); push @triangulation, new Visual::Polyhedron( FacetColor => $Visual::Schlegel::solid_color, VertexLabels => \@points, $decor, Name => "Triangulation of Facet $i of ".$P->name. ", $simplex", Vertices => subset($G->Coord, @points), Facets => $simplex_faces_3d, VertexStyle => "hidden", Closed => 0, ); } ++$i; } $self->Name="Triangulation Boundary of ".$P->name; push @{$self->elements}, \@triangulation; visualize($self); } # Draw the facets of the Schlegel diagram as polytopes. user_method SOLID(%Visual::Polyhedron::decorations) { my ($self, $decor)=@_; my $G=$self->basis_graph; $G->VertexStyle = "hidden"; my $P=$self->Schlegel->Polytope; my @facets; for (my $i = 0; $i < $P->N_FACETS; ++$i) { next if $i==$self->Schlegel->FACET; my $F = new Apps::polytope::RationalPolytope("Facet #$i"); Modules::client("facet",$F,$P,$i,"-relabel"); push @facets, new Visual::Polyhedron( FacetColor => $Visual::Schlegel::solid_color, VertexLabels => $F->VERTEX_LABELS, $decor, Name => $F->name ." of ".$P->name, Vertices => subset($G->Coord, split(/\s+/,$F->VERTEX_LABELS)), Facets => $F->VIF_CYCLIC_NORMAL, FacetNeighbors => $F->NEIGHBOR_FACETS_CYCLIC_NORMAL, VertexStyle => "hidden", Closed => 1, ); } push @{$self->elements}, \@facets; visualize($self); } # Visualize the construction of a 3D Schlegel diagram, that is, the Viewpoint, the 3-polytope and # the projection onto one facet user_method CONSTRUCTION(%Visual::Polyhedron::decorations) { my ($self, $decor)=@_; my $P=$self->Schlegel->Polytope; die "polytope must be 3-dimensional.\n" if $P->DIM != 3; my $VP = new Visual::Polyhedron( EdgeStyle => "thickness 1", $decor, Name => $P->name, Vertices => [ $P->dehomogenize($P->VERTICES) ], Facets => $P->VIF_CYCLIC_NORMAL, FacetNeighbors => $P->NEIGHBOR_FACETS_CYCLIC_NORMAL, FacetStyle => "hidden", VertexStyle => "hidden", ); client("schlegel_vertices_on_facet", $self->Schlegel, $P, "VERTICES", "VERTICES"); $self->basis_graph->Coord = $self->Schlegel->VERTICES; my @graph = ("{0}\n")x($P->N_VERTICES+1); $graph[0] = "{". join(" ",(1..($P->N_VERTICES+1)))."}\n"; my $CG=new Visual::Graph( Name => "Construction of Schlegel diagram of ". $P->name, Graph => \@graph, Coord => [$P->dehomogenize($self->Schlegel->VIEWPOINT), $P->dehomogenize($P->VERTICES)], NodeStyle => "hidden", EdgeColor => "0 0 0", EdgeStyle => "thickness 0.25" ); my $VV=new Visual::PointSet( Name => "Viewpoint of Schlegel diagram of ".$P->name, Points => [$P->dehomogenize($self->Schlegel->VIEWPOINT)], PointStyle =>"thickness 2", PointColor => "0 0 255", PointLabels => ["ViewPoint"] ); $self->basis_graph->EdgeStyle = "thickness 1.5"; push @{$self->elements}, $VP, $CG, $VV; visualize($self); } ################################################################################# package Visual::SchlegelEmbedding; @ISA=qw( Visual::Embedding ); sub compute { unbless($_[0]); my ($Schlegel, $n_vert)=splice @{$_[0]}, 0, 2; $Schlegel->compute_vertices($_[0], @{$_[0]}); $_[0]; } sub get_n_vertices { retrieve($_[0],1); } sub push { my $self=shift; defuse_magic($self); $self->[1] += @_==1 ? scalar(@{$_[0]}) : $_[0]; push @$self, $_[-1]; } ################################################################################# object SchlegelDiagram; function schlegel_embedding { new Visual::SchlegelEmbedding(@_); } function dim(Visual::SchlegelEmbedding) { 3 } # Draw the Schlegel diagram # return: Visual::Schlegel user_method VISUAL(%Visual::Graph::decorations) { my ($self, $decor)=@_; my $P=$self->Polytope; if (!$P->BOUNDED) { die "polytope ", $P->name, " is not BOUNDED and therefore cannot be visualized\n"; } my @edge_colors=($Visual::Color::facets, $Visual::Schlegel::proj_facet); if (exists $decor->{EdgeColor}) { if (is_ARRAY($decor->{EdgeColor}) && @{$decor->{EdgeColor}}==2) { @edge_colors=@{delete $decor->{EdgeColor}}; } elsif (!ref($decor->{EdgeColor})) { $edge_colors[0]=delete $decor->{EdgeColor}; } } my $basis_graph=new Visual::Graph( Name => $P->name, Graph => $P->GRAPH, VertexLabels => $P->lookup("VERTEX_LABELS"), Coord => schlegel_embedding($self, $P->N_VERTICES, "VERTICES"), $decor ); my %proj_facet=map { $_ => 1 } $P->VERTICES_IN_FACETS->[$self->FACET] =~ /\d+/g; visualize( new Visual::Schlegel( Name => "Schlegel diagram of " . $P->name, Schlegel => $self, defaults => { EdgeColor => sub { my ($s, $t)=(shift)->incident_nodes; $edge_colors[$proj_facet{$s} && $proj_facet{$t}] }, }, $basis_graph ) ); } ################################################################################# object Polytope; declare %make_schlegel_params=( FACET => undef, ZOOM => undef ); # category: Visualization # Create a SchlegelDiagram object. # # The projection ray will join the vertex barycenters of the polytope # and the projection facet. # # Default zoom factor is 9/10. # # option: FACET => projection facet index (default: 0) # option: ZOOM => zoom factor (rational or double) # # return: SchlegelDiagram user_method makeSchlegelDiagram(%make_schlegel_params) { my ($this, $params)=@_; my @props=(Polytope => $this, %$params); my $stored_params=$this->lookup("SCHLEGEL_PARAMS"); if (my @stored_params= $stored_params =~ /\A\s* (\d+) \s+ (\S+) \s* ^(.*)$ \s* ^(.*)$/xms) { if (!exists $params->{FACET}) { push @props, (FACET => $stored_params[0], FACET_POINT => $stored_params[2], INNER_POINT => $stored_params[3]); } if (!exists $params->{ZOOM}) { push @props, (ZOOM => $stored_params[1]); } } else { if (!exists $params->{FACET}) { push @props, (FACET => 0); } if (!exists $params->{ZOOM}) { push @props, (ZOOM => "9/10"); } } new Apps::polytope::SchlegelDiagram(@props); } # category: Visualization # Create a Schlegel diagram and draw it. # return: Visual::Schlegel user_method SCHLEGEL(%Visual::Graph::decorations, %make_schlegel_params) { my ($this, $decor, $params)=@_; $this->makeSchlegelDiagram($params)->VISUAL($decor); } # Local Variables: # mode: perl # c-basic-offset:3 # End: