Logo Search packages:      
Sourcecode: magics++ version File versions  Download package

LegendVisitor.cc

/******************************** LICENSE ********************************

 Copyright 2007 European Centre for Medium-Range Weather Forecasts (ECMWF)

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at 

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 ******************************** LICENSE ********************************/

/*! \file LegendNode.cc
    \brief Implementation of the Template class LegendNode.
    \author Graphics Section, ECMWF

    Started: Tue 6-Mar-2007

    Changes:

*/


#include "LegendVisitor.h"
#include "Text.h"
#include "Polyline.h"

#include "Arrow.h"
#include "Symbol.h"
#include "Transformation.h"
#include "Dimension.h"
#include "MagicsFormat.h"
#include "AnimationRules.h"

using namespace magics;

LegendVisitor::LegendVisitor() 
{
      static int i = 0;
      ostringstream n;
      BasicSceneObject::name(n.str());
      Layout::name(n.str());
      i++;
      layout_ = this;
}


LegendVisitor::~LegendVisitor() 
{
}

/*!
 Class information are given to the output-stream.
*/          
void LegendVisitor::print(ostream& out)  const
{
      out << "LegendVisitor[";
            LayoutVisitor::print(out);
      out << "]";
}



void LegendVisitor::visit(BasicGraphicsObjectContainer& tree)
{
      // Noew populate the layout ...
      tree.push_back(layout_);
      // the Layout has been added to a Container, it will be delted automatically!
}


Layout* LegendVisitor::execute(AnimationStep& step, const Layout* visitor) 
{

    if ( this != visitor ) {
            Log::dev() << "DrawingVisitor::execute--> Nothing to do" << endl;
            return 0;
    }
   

    LegendVisitor* legend = new LegendVisitor();
    ((BasicGraphicsObjectContainer*)legend)->parent(const_cast<LegendVisitor* >(this));

   
    //Visitr the step!
    step.visit(*legend);
   legend->build();
    return legend;
   
    //Visitr the step!
    return legend;
    
  
}

void LegendVisitor::visit(BasicSceneObject& parent)
{
      // First visit the parent to collect the legend entry! 
      parent.visit(*this);
      build();
}

void LegendVisitor:: visit(AnimationStep& step)
{
      
}

void LegendVisitor::build()
{
      vector<pair<float, float> > positions;
      
      // adjust the coordinates system!...
      grid(positions);
       blankIt();

      // populate the layout!

    vector<string>::const_iterator label = lines_.begin();        
      vector<pair<float, float> >::const_iterator position = positions.begin();     
      if ( title_ ) {
                  Text* legend = new Text();
                (*legend).addText(title_text_, Colour(*colour_), LegendVisitorAttributes::height_);
                (*legend).push_back(PaperPoint(1,0));
                layout_->push_back(legend);
      }
      
      for(vector<LegendEntry*>::const_iterator entry = begin(); entry != end(); ++entry) {
            Text* legend = new Text();
            
            (*entry)->set(*this);
            string text = ( label != lines_.end() && !label->empty() ) ? *label : (*entry)->label();              
            (*legend).addText(text, Colour(*colour_), LegendVisitorAttributes::height_);
            (*legend).setVerticalAlign(MHALF);
            if ( ! lines_.empty() ) {
                  ++label;          
                  if (label == lines_.end()) --label;
            }
            if (text=="ignore") continue;
          (magCompare(direction_, "column") ) ? 
                  (*method_).column(**entry, position->first, position->second, *legend, *this) :
                  (*method_).row(**entry, position->first, position->second, *legend, *this);
            
            
            ++position;
              layout_->push_back(legend);
      }
   frameIt();
}
 




void LegendVisitor::grid(vector<pair<float, float> >& positions)
{
    if ( magCompare(direction_, "automatic")  ) {
      if ( layout_->absoluteWidth() <  layout_->absoluteHeight() ) 
            direction_ = "column";
      }

      unsigned int count = 0;
      vector<string>::const_iterator label = lines_.begin();            
      
      for(vector<LegendEntry*>::const_iterator entry = begin(); entry != end(); ++entry)
      {           
            string text = ( label != lines_.end() && !label->empty() ) ? *label : (*entry)->label();              
                  
            if ( ! lines_.empty() ) {
                  ++label;          
                  if (label == lines_.end()) --label;
            }
            if (text=="ignore") continue;
            count++;
      }
      if (magCompare(direction_, "column") ){
            int row = 1;
            int column = 1;
            int rows = 0;
            // calclate the number of rows we need! 
            rows= count/columns_+1;
            for (unsigned int i = 0; i < count; i++ ) {     
                  Log::debug() << "add position [" <<  column << ", " << row << "]" << endl;                             
                  positions.push_back(make_pair(column, row));
                  row++;
                  if (row > rows ) {            
                        row = 1;
                        column+=2;
                   }
            }
            layout_->setCoordinates(  -0.2, columns_*2 + 0.5,  0, rows + 1);
            return;
      }

      int rows = 1;
      int column = 0;

      for (unsigned int i = 0; i < count; i++ ) {     
            Log::debug() << "add position [" <<  column*2+1 << ", " << rows << "]" << endl;
             positions.push_back(make_pair(column*2+1, rows));
             column++;
             if ( columns_ > 1 && column >= columns_ ) {          
                  column = 0;
                  rows++;
             }
      }

      int nb = ( columns_ > 1) ? columns_: count;

      if ( title_ ) {
            layout_->setCoordinates(nb*2 + 0.5, -0.5,  rows + 0.5, -2);
      }
      else 
            layout_->setCoordinates(-0.5, nb*2 + 0.5,  rows + 0.5, 0);
}

void SymbolEntry::set(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
      double width = 0.5;
      double height = 0.2;
      double incx=0.1;
      double incy=0.1;

      double x = point.x();
      double y = point.y();
      Polyline*  frame = new Polyline();

      frame->setColour(Colour("black"));
      frame->push_back(PaperPoint(x-width, y-height));
      frame->push_back(PaperPoint(x-width, y+height));
      frame->push_back(PaperPoint(x, y+height));
      frame->push_back(PaperPoint(x, y-height));
      frame->push_back(PaperPoint(x-width, y-height));            
      legend.push_back(frame);
      for (float px =x - width+ incx; px < x; px+=incx )
            for (float py =y - height+ incy; py < y+height; py+=incy )
                  symbol_->push_back(PaperPoint(px, py));

       legend.push_back(symbol_);
}

Colour SymbolEntry::colour()
{
      return symbol_->getColour();
}

void ArrowEntry::set(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
      PaperPoint pos(point.x()-0.1, point.y());
      arrow_->push_back(ArrowPoint(arrow_->getScale(), 0, pos));
      legend.push_back(arrow_);
}

Colour BoxEntry::colour()
{
      return box_->getFillColour();
}

void LegendEntry::rowBox(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
      Polyline*  box = new Polyline();
      FillShadingProperties* shading = new FillShadingProperties();    
      //Normall the pilyline left the low value on their left!
      box->setFillColour(colour());
      box->setShading(shading);
      
      Polyline*  frame = new Polyline();
      Log::debug() << "BoxEntry--->set at " << point << endl;
      double width = 0.8;
      double height = 0.5;
      double x = point.x();
      double y = point.y();
      
      box->push_back(PaperPoint(x-width, y-height));
      box->push_back(PaperPoint(x-width, y+height));
      box->push_back(PaperPoint(x+2, y+height));
      box->push_back(PaperPoint(x+2, y-height));
      box->push_back(PaperPoint(x-width, y-height));
      box->setColour(Colour("black"));
      frame->setColour(Colour("black"));
      frame->push_back(PaperPoint(x-width, y-height));
      frame->push_back(PaperPoint(x-width, y+height));
      frame->push_back(PaperPoint(x+2, y+height));
      frame->push_back(PaperPoint(x+2, y-height));
      frame->push_back(PaperPoint(x-width, y-height));

//    Log::debug() << " Size of polylineSet--> " << set->size() << "=" << set->front()->size() << endl;

      legend.push_back(frame);
}

void LegendEntry::columnBox(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
      
      Polyline*  box = new Polyline();
      FillShadingProperties* shading = new FillShadingProperties();    
      box->setFillColour(colour());
      
    
      box->setShading(shading);

      Polyline*  frame = new Polyline();
      Log::debug() << "BoxEntry--->set at " << point << "Colour-> " << colour() << endl;
      
      double x = point.x();
      double y = point.y();
      double width = 0.4;
      double height = 0.5;
      
      box->push_back(PaperPoint(x-width, y-height));
      box->push_back(PaperPoint(x-width, y+height));
      box->push_back(PaperPoint(x, y+height));
      box->push_back(PaperPoint(x, y-height));
      box->push_back(PaperPoint(x-width, y-height));
      box->setColour(Colour("black"));
      frame->setColour(Colour("black"));
      frame->push_back(PaperPoint(x-width, y-height));
      frame->push_back(PaperPoint(x-width, y+height));
      frame->push_back(PaperPoint(x, y+height));
      frame->push_back(PaperPoint(x, y-height));
      frame->push_back(PaperPoint(x-width, y-height));
      
//    Log::debug() << " Size of polylineSet--> " << set->size() << "=" << set->front()->size() << endl;
      
      legend.push_back(frame);
      
      
      ostringstream top, bottom;
            top << MagicsFormat(format_) << from_; 
            bottom << MagicsFormat(format_) << to_; 
            Log::debug() << "BoxEntry top--->" << top.str() << endl;
            Log::debug() << "BoxEntry bottom---> " << bottom.str() << endl;
      
            Text* from = new Text();
                  Text* to = new Text();
                  from->setVerticalAlign(MHALF);
                  
                  to->setVerticalAlign(MHALF);        
                  from->addText(top.str(), font_);
            
                  to->addText(bottom.str(), font_);

                  to->push_back(PaperPoint(x+0.25, y + height));
                  from->push_back(PaperPoint(x+0.25, y - height));

                  legend.push_back(from);
               legend.push_back(to);
}

void EmptyEntry::rowBox(const PaperPoint&, BasicGraphicsObjectContainer&)
{           
}

void EmptyEntry::columnBox(const PaperPoint& point , BasicGraphicsObjectContainer& legend)
{
      Polyline*  box = new Polyline();
      FillShadingProperties* shading = new FillShadingProperties();    
      //Normall the pilyline left the low value on their left!
      box->setFillColour( Colour("NONE"));

      box->setShading(shading);

      Polyline*  frame = new Polyline();
      Log::debug() << "BoxEntry--->set at " << point << "Colour-> " << colour() << endl;

      double x = point.x();
      double y = point.y();
      double width = 0.4;
      double height = 0.5;

      box->push_back(PaperPoint(x-width, y-height));
      box->push_back(PaperPoint(x-width, y+height));
      box->push_back(PaperPoint(x, y+height));
      box->push_back(PaperPoint(x, y-height));
      box->push_back(PaperPoint(x-width, y-height));
      box->setColour(Colour("black"));
      frame->setColour(Colour("black"));
            frame->push_back(PaperPoint(x-width, y-height));
            frame->push_back(PaperPoint(x-width, y+height));
            frame->push_back(PaperPoint(x, y+height));
            frame->push_back(PaperPoint(x, y-height));
            frame->push_back(PaperPoint(x-width, y-height));

      //    Log::debug() << " Size of polylineSet--> " << set->size() << "=" << set->front()->size() << endl;

      legend.push_back(frame);
}

void BoxEntry::set(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
      Log::debug() << "BoxEntry--->set at " << point << endl;
      double width = 0.5;
      double height = 0.2;
      double x = point.x();
      double y = point.y();
      box_->push_back(PaperPoint(x-width, y-height));
      box_->push_back(PaperPoint(x-width, y+height));
      box_->push_back(PaperPoint(x, y+height));
      box_->push_back(PaperPoint(x, y-height));
      box_->push_back(PaperPoint(x-width, y-height));
      box_->setColour(Colour("black"));

      legend.push_back(box_); 
}


void BoxEntry::rowBox(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
//    ShadingProperties* shading = box_->getShading();    
      //Normall the pilyline left the low value on their left!

      Log::debug() << "BoxEntry--->set at " << point << endl;
      double width = 1;
      double height = 0.25;
      double x = point.x();
      double y = point.y();

      ostringstream top, bottom;
      top << MagicsFormat(format_) << to_; 
      bottom << MagicsFormat(format_) << from_; 

      Text* from = new Text();
      Text* to = new Text();

      from->addText(top.str(), font_);
      to->addText(bottom.str(), font_);
      
      to->push_back(PaperPoint(x-width, y - height - 0.25));
      from->push_back(PaperPoint(x+width, y - height- 0.25));
      from->setVerticalAlign(MBOTTOM);
      to->setVerticalAlign(MBOTTOM);

      legend.push_back(from);
      legend.push_back(to);

//    Polyline* frame = new Polyline();

      box_->push_back(PaperPoint(x-width, y-height));
      box_->push_back(PaperPoint(x-width, y+height+height));
      box_->push_back(PaperPoint(x+width, y+height+height));
      box_->push_back(PaperPoint(x+width, y-height));
      box_->push_back(PaperPoint(x-width, y-height));
      box_->setColour(Colour("black"));

      legend.push_back(box_);
}

void BoxEntry::columnBox(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
//    ShadingProperties* shading = box_->getShading();    
      //Normall the pilyline left the low value on their left!    shading->inColour_ = box_->getShading()->right_;

//    double min = from_;
//    double max = std::max(from_, to_);

      Log::debug() << "BoxEntry--->set at " << point << endl;
      double width = 0.4;
      double height = 0.5;
      double x = point.x()-0.2;
      double y = point.y();
      
      ostringstream top, bottom;
      bottom << MagicsFormat(format_) << to_; 
      top << MagicsFormat(format_) << from_; 

      Text* from = new Text();
      Text* to = new Text();

      from->setVerticalAlign(MHALF);
      to->setVerticalAlign(MHALF);
      from->addText(top.str(), font_);
      to->addText(bottom.str(), font_);

      to->push_back(PaperPoint(x+0.55, y + height));
      from->push_back(PaperPoint(x+0.55, y - height));

      legend.push_back(from);
      legend.push_back(to);

      box_->push_back(PaperPoint(x-width, y-height));
      box_->push_back(PaperPoint(x-width, y+height));
      box_->push_back(PaperPoint(x, y+height));
      box_->push_back(PaperPoint(x, y-height));
      box_->push_back(PaperPoint(x-width, y-height));
      box_->setColour(Colour("black"));
      
      legend.push_back(box_);
}

Colour LineEntry::colour() 
{
      return line_->getColour();
}

void LineEntry::set(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
      Log::debug() << "LineEntry--->set at " << point << endl;
      double width = 0.4;
      double x = point.x();
      double y = point.y();
      line_->push_back(PaperPoint(x-width, y)); 
      line_->push_back(PaperPoint(x+width, y));
      legend.push_back(line_);
}

void LegendVisitor::getReady()
{}

void XmlLegendVisitor::getReady()
{
      if ( standalone_ ) { 
            StandaloneLayout* layout = new StandaloneLayout();
             layout->path(standalone_path_);
             layout->format(standalone_format_);
             layout->outputWidth(standalone_width_);
             layout->outputHeight(standalone_height_);
             
             layout_= layout;
             BasicGraphicsObjectContainer::push_back(layout_);    
             layout_->frame(blanking_, border_, *border_colour_, border_style_, border_thickness_);    
             return;
      }
      else {
            layout_= this;
      }
            
      
            assert(BasicSceneObject::parent_);
            Dimension bottom(bottom_, BasicSceneObject::parent_->absoluteWidth(), 0);
            Dimension left(left_, BasicSceneObject::parent_->absoluteHeight(), 0);
            Dimension width(XmlBasicNodeAttributes::width_, BasicSceneObject::parent_->absoluteWidth(), 100);
            Dimension height(XmlBasicNodeAttributes::height_, BasicSceneObject::parent_->absoluteHeight(), 100);

            Dimension mb(margin_bottom_, height.absolute(), 0);   
            Dimension ml(margin_left_, width.absolute(), 0);
            Dimension mr(margin_right_, width.absolute(), 0);
            Dimension mt(margin_top_, height.absolute(), 0);

      // We have to calculate the new x, y, width, height

            double xl = ml.percent()*width.absolute()/100;
            double xr = mr.percent()*width.absolute()/100;
            double yb = mb.percent()*height.absolute()/100;
//          double yt = mt.percent()*height.absolute()/100;

      double text_x =  left.percent() + xl *100/BasicSceneObject::parent_->absoluteWidth();
      double text_y =  bottom.percent()+ yb *100/BasicSceneObject::parent_->absoluteHeight();;

      double text_width = width.percent();
      double text_height = height.percent();

      if ( ( text_height + text_y ) > 100 ) 
            text_height = 100 - text_y ;
      if ( ( text_width + text_x ) > 100 ) 
                  text_width = 100 - text_x ;

      layout_->x(text_x);
      layout_->y(text_y);
      layout_->width(text_width-  xr *100/BasicSceneObject::parent_->absoluteWidth());
      layout_->height(text_height-  xr *100/BasicSceneObject::parent_->absoluteWidth());
      

      layout_->display( XmlBasicNodeAttributes::display_); 
      
      
}

void FortranPositionalLegendVisitor::getReady()
{
      Log::dev() << "FortranLegendVisitor::getReady()" << endl;
      x(LegendBoxAttributes::x_ / BasicPositionalObject::absoluteWidth() *100);
      y(LegendBoxAttributes::y_ / BasicPositionalObject::absoluteHeight() *100);
      width(LegendBoxAttributes::width_ / BasicPositionalObject::absoluteWidth() *100);
      height( LegendBoxAttributes::height_ / BasicPositionalObject::absoluteHeight() *100);
      layout_ = this;
      Layout::frame(blanking_, border_, *border_colour_, border_line_style_, border_thickness_);
      //border(border_, *border_colour_, border_line_style_, border_thickness_);
}


void FortranAutomaticLegendVisitor::getReady()
{
      Log::dev() << "FortranAutomaticTextNode::getReady()" << endl;
      x(5);
      y(80);
      width(80);
      height(15);
}

void LegendEntry::set(const LegendVisitorAttributes& attributes)
{
      format_ = attributes.getFormat();

      font_ = MagFont("helvetica");
      font_.size(attributes.getHeight());
      font_.colour(attributes.getColour());
      
}

void SimpleSymbolEntry::set(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
      double x = point.x()- 0.2;
      double y = point.y();
            
      symbol_->push_back(PaperPoint(x, y));
                        
       legend.push_back(symbol_);
}

Colour SimpleSymbolEntry::colour()
{
      return symbol_->getColour();
}

Generated by  Doxygen 1.6.0   Back to index