# Visualization Library A lightweight C++ OpenGL middleware for 2D/3D graphics | [Home] [Tutorials] [All Classes] [Grouped Classes]

# Interpolators Tutorial

In this tutorial you will learn how to use the various interpolator classes to generate splines and smooth aniamtions.

You can also use an interpolator to generate paths and silhouettes for the vl::Extrusion class.

Generated by `showCatmullRomPentagonOpen()` | Generated by `showCatmullRomPentagonClosed()` | Generated by `showLinearPentagon()` | Generated by `showInterpolatorAnimation()`

[From `App_Interpolators.hpp`]

    class App_Interpolators: public BaseDemo
    {
    public:
      // Constructor.
      App_Interpolators()
      {
        mTest = 0;
        mLinearInterpolator     = new vl::LinearInterpolatorFVec3;
        mCatmullRomInterpolator = new vl::CatmullRomInterpolatorFVec3;
        mTransform1 = new vl::Transform; // will follow linear interpolation
        mTransform2 = new vl::Transform; // will follow Catmull-Rom interpolation
        vl::VisualizationLibrary::rendering()->as<vl::Rendering>()->transform()->addChild(mTransform1.get());
        vl::VisualizationLibrary::rendering()->as<vl::Rendering>()->transform()->addChild(mTransform2.get());
      }

      void showCatmullRomPentagonOpen()
      {
        // generate the pentagon control points
        std::vector<vl::fvec3> pentagon;
        float radius = 5.0f;
        for(int i=0; i<5; ++i)
        {
          float a = (float)i/5.0f*vl::fPi*2.0f + vl::fPi/2.0f;
          pentagon.push_back(vl::fvec3(cos(a)*radius,sin(a)*radius,0));
        }
        // show the pentagon
        showPath(pentagon, vlut::green);

        // Catmull-Rom interpolation over the pentagon control points
        std::vector<vl::fvec3> pentagon_spline;
        vl::CatmullRomInterpolatorFVec3 catmull;
        catmull.interpolator()->setPath( pentagon );
        // automatically generate the appropriate Catmull-Rom spline end-points
        catmull.interpolator()->setupEndPoints(false/*loop = no*/);
        // sample the spline over 41 points
        int segments = 41;
        for(int i=0; i<segments; ++i)
        {
          float t = (float)i/(segments-1); // interpolate from 0.0 to 1.0 included
          pentagon_spline.push_back( catmull.computePoint(t) );
        }
        // show the interpolated pentagon
        showPath(pentagon_spline, vlut::red, true/*show points*/);
      }

      void showCatmullRomPentagonLoop()
      {
        // generate the pentagon
        std::vector<vl::fvec3> pentagon;
        float radius = 5.0f;
        for(int i=0; i<5; ++i)
        {
          float a = (float)i/5.0f*vl::fPi*2.0f + vl::fPi/2.0f;
          pentagon.push_back(vl::fvec3(cos(a)*radius,sin(a)*radius,0));
        }
        showPath(pentagon, vlut::green);

        // Catmull-Rom interpolation over the pentagon
        vl::CatmullRomInterpolatorFVec3 catmull;
        catmull.interpolator()->setPath( pentagon );
        std::vector<vl::fvec3> pentagon_loop;
        // automatically generate the appropriate Catmull-Rom spline end-points
        catmull.interpolator()->setupEndPoints(true/*loop = yes*/);
        int segments = 50;
        for(int i=0; i<segments; ++i)
        {
          // interpolate from 0 to 0.9x, never reach 1.0 otherwise the last point would be the same as the first one
          float t = (float)i/segments;
          pentagon_loop.push_back( catmull.computePoint(t) );
        }
        showPath(pentagon_loop, vlut::yellow, true/*show points*/, true/*close line loop*/);
      }

      void showLinearPentagon()
      {
        // generate the pentagon
        std::vector<vl::fvec3> pentagon;
        float radius = 5.0f;
        for(int i=0; i<5; ++i)
        {
          float a = (float)i/5.0f*vl::fPi*2.0f + vl::fPi/2.0f;
          pentagon.push_back(vl::fvec3(cos(a)*radius,sin(a)*radius,0));
        }
        showPath(pentagon, vlut::green);

        // linear interpolation over the pentagon
        vl::LinearInterpolatorFVec3 linear;
        linear.interpolator()->setPath( pentagon );
        std::vector<vl::fvec3> pentagon_linear;
        int segments = 20; /* 21 would perfectly overlap the pentagon */
        for(int i=0; i<segments; ++i)
        {
          // interpolate from 0 to 1.0
          float t = (float)i/(segments-1);
          pentagon_linear.push_back( linear.computePoint(t) );
        }
        vl::Actor* line = showPath(pentagon_linear, vlut::blue, true/*show points*/);
        // ensure the blue line is over the green one.
        line->setRenderRank(1);
      }

      // creates two paths one linearly-interpolated and the other Catmull-Rom-interpolated
      void showInterpolatorAnimation()
      {
        // generate a 5-points star.
        std::vector<vl::fvec3> pentagon;
        float radius = 5.0f;
        for(int i=0; i<5; ++i)
        {
          float a = (float)i/5.0f*vl::fPi*2.0f*2.0f + vl::fPi/2.0f;
          pentagon.push_back(vl::fvec3(cos(a)*radius,sin(a)*radius,0));
        }

        // Catmull-Rom interpolation over the star
        mCatmullRomInterpolator->interpolator()->setPath( pentagon );
        // generate line for visual feedback.
        std::vector<vl::fvec3> pentagon_loop;
        // automatically generate the appropriate Catmull-Rom spline end-points
        mCatmullRomInterpolator->interpolator()->setupEndPoints(true/*loop = yes*/);
        int segments = 50;
        for(int i=0; i<segments; ++i)
        {
          // interpolate from 0 to 0.9x, never reach 1.0 otherwise the last point would be the same as the first one
          float t = (float)i/segments;
          pentagon_loop.push_back( mCatmullRomInterpolator->computePoint(t)*1.2f /*1.2f -> makes it a bit larger*/ );
        }
        showPath(pentagon_loop, vlut::yellow, true/*show points*/, true/*close line loop*/);

        // linear interpolation over the star (loop)
        mLinearInterpolator->interpolator()->setPath( pentagon );
        // close the pentagon
        mLinearInterpolator->interpolator()->path().push_back(pentagon[0]);
        // generate line for visual feedback.
        std::vector<vl::fvec3> pentagon_linear;
        segments = 20;
        for(int i=0; i<segments; ++i)
        {
          // interpolate from 0 to 0.9x, never reach 1.0 otherwise the last point would be the same as the first one
          float t = (float)i/segments;
          pentagon_linear.push_back( mLinearInterpolator->computePoint(t) );
        }
        showPath(pentagon_linear, vlut::blue, true/*show points*/, true/*close line loop*/);

        // display animated arrows
        vl::ref<vl::Geometry> arrow = vlut::makePyramid(vl::vec3(0,0,0),0.5f,1.0f);
        arrow->transform( vl::mat4::rotation(-90.0f,1,0,0) );
        arrow->computeNormals();
        vl::ref<vl::Effect> arrow_fx = new vl::Effect;
        arrow_fx->shader()->enable(vl::EN_DEPTH_TEST);
        arrow_fx->shader()->enable(vl::EN_LIGHTING);
        arrow_fx->shader()->setRenderState(new vl::Light(0));
        sceneManager()->tree()->addActor( arrow.get(), arrow_fx.get(), mTransform1.get() );
        sceneManager()->tree()->addActor( arrow.get(), arrow_fx.get(), mTransform2.get() );
      }

      // displays a closed or open path, with or without points
      vl::Actor* showPath(const std::vector<vl::fvec3>& ctrl_points, const vl::fvec4& color, bool points=false, bool loop=false)
      {
        // simple effect
        vl::ref<vl::Effect> effect = new vl::Effect;
        effect->shader()->enable(vl::EN_DEPTH_TEST);
        effect->shader()->gocPointSize()->set(4);

        // generates the line/points geometry
        vl::ref<vl::Geometry>   geom       = new vl::Geometry;
        vl::ref<vl::ArrayFVec3> vert_array = new vl::ArrayFVec3;
        geom->setVertexArray( vert_array.get() );
        *vert_array = ctrl_points;
        geom->setColorArray(color);
        geom->primitives()->push_back(new vl::DrawArrays(loop ? vl::PT_LINE_LOOP : vl::PT_LINE_STRIP, 0, vert_array->size()));
        if (points)
          geom->primitives()->push_back(new vl::DrawArrays(vl::PT_POINTS, 0, vert_array->size()));

        // adds the geometry to the scene
        return sceneManager()->tree()->addActor( geom.get(), effect.get(), NULL );
      }

      // Animates the arrows along the path.
      void run()
      {
        if (mTest == 3)
        {
          float delta = 1.0f/50.0f;
          vl::fvec3 up(0,0,1);
          // get the fractional part of the time to loop 0..1
          float eye  = vl::fract((float)vl::Time::currentTime() * 0.1f);
          float look = vl::fract(eye+delta); // we have to remain in the range 0..1
          vl::fmat4 m;
          // linear interpolation
          m = vl::fmat4::lookAt(mLinearInterpolator->computePoint(eye),mLinearInterpolator->computePoint(look),up);
          mTransform1->setLocalMatrix((vl::mat4)m);
          // Catmull-Rom interpolation
          m = vl::fmat4::lookAt(mCatmullRomInterpolator->computePoint(eye)*1.2f,mCatmullRomInterpolator->computePoint(look)*1.2f,up);
          mTransform2->setLocalMatrix((vl::mat4)m);
        }
      }

      // Press the left/right arrow buttons to navigate through the examples.
      void keyPressEvent(unsigned short ch, vl::EKey key)
      {
        BaseDemo::keyPressEvent(ch,key);

        if (key == vl::Key_Left || key == vl::Key_Right)
        {
          if (key == vl::Key_Left)
            mTest--;
          if (key == vl::Key_Right)
            mTest++;
          if (mTest < 0) mTest = 3;
          if (mTest > 3) mTest = 0;
          sceneManager()->tree()->actors()->clear();
          switch(mTest)
          {
            case 0: showCatmullRomPentagonOpen(); break;
            case 1: showCatmullRomPentagonLoop(); break;
            case 2: showLinearPentagon(); break;
            case 3: showInterpolatorAnimation(); break;
          }
          showText();
        }
      }

      // displays the text
      void showText()
      {
        vl::ref<vl::Text> text = new vl::Text;
        text->setText("Press the left/right arrow keys to change test.");
        text->setFont( vl::VisualizationLibrary::fontManager()->acquireFont("/font/bitstream-vera/VeraMono.ttf", 10) );
        text->setAlignment( vl::AlignHCenter | vl::AlignTop );
        text->setViewportAlignment( vl::AlignHCenter | vl::AlignTop );
        text->translate(0,-5,0);
        text->setColor(vlut::white);
        vl::ref<vl::Effect> effect = new vl::Effect;
        effect->shader()->enable(vl::EN_BLEND);
        sceneManager()->tree()->addActor(text.get(), effect.get());
      }

      void initEvent()
      {
        BaseDemo::initEvent();
        showCatmullRomPentagonOpen();
        showText();
      }

    protected:
      int mTest;
      vl::ref<vl::LinearInterpolatorFVec3>     mLinearInterpolator;
      vl::ref<vl::CatmullRomInterpolatorFVec3> mCatmullRomInterpolator;
      vl::ref<vl::Transform> mTransform1;
      vl::ref<vl::Transform> mTransform2;
    };

    // Have fun!

Visualization Library v2009.08 Reference Documentation
Copyright 2005-2009 Michele Bosi. All rights reserved.
Updated on Sun Nov 29 11:11:40 2009.
Permission is granted to use this page to write and publish articles regarding Visualization Library.