uniform_distortion_example.cpp

Back to Uniform distortion

example/PastelExample/

// Description: Uniform distortion example
// DocumentationOf: uniform_distortion.h

#include "pastel_example.h"

#include "pastel/math/uniform_distortion.h"

#include "pastel/geometry/poisson_disk_pattern.h"

#include "pastel/gfx/savepcx.h"
#include "pastel/gfx/drawing.h"
#include "pastel/gfx/color_space.h"
#include "pastel/gfx/color_tools.h"

#include "pastel/sys/random.h"
#include "pastel/sys/views.h"
#include "pastel/sys/string_algorithms.h"

using namespace Pastel;

namespace
{

    void draw(const std::vector<Vector2>& sample,
        integer x, integer y, const Color& color,
        Array<Color, 2>& image)
    {
        const integer samples = sample.size();
        for (integer i = 0;i < samples;++i)
        {
            drawPixel(Vector<integer, 2>(x + sample[i].x() * 100,
                y + sample[i].y() * 100),
                color, arrayView(image));
        }
    }

    Color myRandoColor()
    {
        return hsvToRgb(randomRgbColor() * Color(1, 1, 0.1) + Color(0, 0, 0.9));
    }

    void test()
    {
        const integer Width = 600;
        const integer Height = 600;

        Array<Color, 2> image(Vector2i(Width, Height));

        std::vector<Vector2> square;

        /*

       for (integer i = 0;i < Samples;++i)
       {
           square.push_back(Vector2(
               random<real>(),
               random<real>()));
       }
       */

        const integer XGrids = 10;
        const integer YGrids = 10;

        const integer XSamples = 400;
        const integer YSamples = 400;

        const real xDelta = (real)1 / XSamples;
        const real yDelta = (real)1 / YSamples;

        const real xGridDelta = (real)1 / (XGrids - 1);
        const real yGridDelta = (real)1 / (YGrids - 1);

        for (integer y = 0; y < YGrids;++y)
        {
            for (integer x = 0;x < XSamples;++x)
            {
                square.push_back(Vector2(
                    x * xDelta, y * yGridDelta));
            }
        }

        for (integer x = 0; x < XGrids;++x)
        {
            for (integer y = 0;y < YSamples;++y)
            {
                square.push_back(Vector2(
                    x * xGridDelta, y * yDelta));
            }
        }

        draw(square, 0, 0, myRandoColor(), image);

        const integer Samples = square.size();

        {
            std::vector<Vector2> pointList;
            pointList.reserve(Samples);

            for (integer i = 0;i < Samples;++i)
            {
                pointList.push_back(
                    (uniformlySampleBall(square[i]) + 1) / 2);
            }

            draw(pointList, 150, 0, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;
            pointList.reserve(Samples);

            for (integer i = 0;i < Samples;++i)
            {
                pointList.push_back(
                    uniformlySampleSimplex(square[i]));
            }
            draw(pointList, 300, 0, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;
            pointList.reserve(Samples);

            for (integer i = 0;i < Samples;++i)
            {
                pointList.push_back(
                    (uniformlySampleAnnulus(square[i], 0.5, 1) + 1) / 2);
            }
            draw(pointList, 300, 150, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;
            const integer points = 25;

            for (integer i = 0;i < points;++i)
            {
                pointList.push_back(
                    (uniformlySampleSphere(Vector1((real)i / (points - 1))) + 1) / 2);
            }
            draw(pointList, 150, 150, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;
            const integer points = 25;

            for (integer i = 0;i < points;++i)
            {
                pointList.push_back(
                    (uniformlySampleHemisphere(Vector1((real)i / (points - 1))) + 1) / 2);
            }
            draw(pointList, 0, 150, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;
            const integer points = 25;

            for (integer i = 0;i < points;++i)
            {
                pointList.push_back(
                    (cosineSampleHemisphere(Vector1((real)i / (points - 1))) + 1) / 2);
            }
            draw(pointList, 0, 300, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;
            const integer points = 100;

            for (integer i = 0;i < points;++i)
            {
                pointList.push_back(
                    shrink((randomVectorBall<real, 3>() + 1) / 2));
            }
            draw(pointList, 150, 300, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;

            for (integer i = 0;i < Samples;++i)
            {
                pointList.push_back(
                    shrink((uniformlySampleSphere(square[i]) + 1) / 2));
            }
            draw(pointList, 300, 300, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;

            for (integer i = 0;i < Samples;++i)
            {
                pointList.push_back(
                    shrink((uniformlySampleHemisphere(square[i]) + 1) / 2));
            }
            draw(pointList, 0, 450, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;

            for (integer i = 0;i < Samples;++i)
            {
                pointList.push_back(
                    shrink((cosineSampleHemisphere(square[i]) + 1) / 2));
            }
            draw(pointList, 150, 450, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;
            const integer points = 100;

            for (integer i = 0;i < points;++i)
            {
                pointList.push_back(
                    (randomVectorBall<real, 2>() + 1) / 2);
            }
            draw(pointList, 300, 450, myRandoColor(), image);
        }

        savePcx(image, "uniform_distortion.pcx");
    }

    class PushBack
    {
    public:
        explicit PushBack(
            std::vector<Vector2>& data)
            : data_(data)
        {
        }

        void operator()(const Vector2& that) const
        {
            data_.push_back(that);
        }

        std::vector<Vector2>& data_;
    };

    void test2()
    {
        const integer Width = 500;
        const integer Height = 250;

        Array<Color, 2> image(Vector2i(Width, Height));

        std::vector<Vector2> square;
        PushBack pushBack(square);

        poissonDiskPattern(
            AlignedBox2(0, 0, 1, 1),
            0.05, pushBack);

        draw(square, 0, 0, myRandoColor(), image);

        const integer Samples = square.size();

        {
            std::vector<Vector2> pointList;
            pointList.reserve(Samples);

            for (integer i = 0;i < Samples;++i)
            {
                pointList.push_back(
                    (uniformlySampleBall(square[i]) + 1) / 2);
            }

            draw(pointList, 150, 0, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;
            pointList.reserve(Samples);

            for (integer i = 0;i < Samples;++i)
            {
                pointList.push_back(
                    uniformlySampleSimplex(square[i]));
            }
            draw(pointList, 300, 0, myRandoColor(), image);
        }

        {
            std::vector<Vector2> pointList;
            pointList.reserve(Samples);

            for (integer i = 0;i < Samples;++i)
            {
                pointList.push_back(
                    (uniformlySampleAnnulus(square[i], 0.5, 1) + 1) / 2);
            }
            draw(pointList, 300, 150, myRandoColor(), image);
        }

        savePcx(image, "uniform_sampling_distortion.pcx");
    }

    template <typename Real, int N>
    void testDistance()
    {
        const integer Samples = 100000;
        std::vector<Vector<Real, N> > pointList;
        pointList.reserve(Samples);

        const integer Width = 512;
        const integer Height = 512;

        std::vector<integer> histogram(Width, 0);

        for (integer i = 0;i < Samples;++i)
        {
            const Vector<Real, N> sample
                = randomVectorBall<Real, N>();
            const Real distance = 
                norm(sample);
            ++histogram[quantizeUnsigned(distance, Width)];
        }

        integer maxBin = 0;
        for (integer i = 0;i < Width;++i)
        {
            if (histogram[i] > maxBin)
            {
                maxBin = histogram[i];
            }
        }

        Array<Color, 2> image(Vector2i(Width, Height), Color(1, 1, 1));
        for (integer x = 0;x < Width;++x)
        {
            const real t = dequantizeUnsigned(x, Width);
            drawVerticalLine(x, 0, 
                dequantizeUnsigned(histogram[x], maxBin + 1) * Height,
                linear(Color(0, 0, 0), Color(0, 0, 0.2), t), 
                arrayView(image));
        }

        savePcx(image, "test_uniform_sampling_distance_" + integerToString(N, 2) + ".pcx");
    }

    void addTest()
    {
        testRunner().add("UniformSampling_1", test);
        testRunner().add("UniformSampling_2", test2);
        testRunner().add("UniformSampling_Distance_2", testDistance<real, 2>);
        testRunner().add("UniformSampling_Distance_8", testDistance<real, 8>);
    }

    CallFunction run(addTest);

}