Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw Line using c++ without graphics

Tags:

c++

I wish to write program that draw line using c++ lang without using graphics library I tried a lot but I don't reach to the result which I want the line equation is :

y=mx+b

I want to draw this line (for example)

y=3x+2

this is my code

#include <iostream>
#include <math.h>

using namespace std;

int pth (int x)  {
    return 2*x-3;
}

int main()  {
    int i,j,y;
    for (int x=-10;x <= 10;x++)  {
        for ( i=-10;i <= x;i++)  {
            if (i==x) {
                y=pth(x);
                cout<<"x=";
                cout<<x;
                cout<<"y=";
                cout<<y;

                for(j=-10;j<=y;j++) {
                    if(j==y)
                        cout << "*";
                    else
                        cout << " ";
                }
            }
        }
        cout << "\n";
    }
    cin.get();
    return 0;
 }

the output is like this

x=0y=3   *
 x=1y=5     *
  x=2y=7       *
   x=3y=9         *
    x=4y=11           *
     x=5y=13             *
      x=6y=15               *
       x=7y=17                 *
        x=8y=19                   *
         x=9y=21                     *
          x=10y=23                       *

but for the given equation (y=2x-3) the result must be

                                      *
                                  *
                              *
                           *
                        *
                    *
                 *

the code is right as I think but the problem is how to determine the direction of the line so it will draw correctly

like image 489
M.Bwe Avatar asked Dec 11 '17 13:12

M.Bwe


1 Answers

Because I like a challenge, I made a tiny Canvas class, to be used like:

int main() {
    using Canvas = BasicCanvas<160, 80>;
    Canvas canvas;
    canvas.origin = {canvas.cols()/3, canvas.rows()/3};

    canvas.axes();

    canvas.plot([](double x) { return  x; });
    canvas.plot([](double  ) { return -8; });
    canvas.plot([](double x) { return 3*log(x); });
    canvas.plot([](double x) { return 4*sin(x/2); });
    canvas.plot([](double x) { return 24*cos(x/12); });

    std::cout << canvas;
}

Which prints enter image description here

Or commenting out the origin assignment: enter image description here

Implementation

The implementation basically iterates through the positions on the x axis and plots approximate line drawing characters depending on the angle (first derivative) of the function at that point:

template <size_t Columns = 100, size_t Rows = 50>
struct BasicCanvas {
    using Line   = std::array<char, Columns>;
    using Screen = std::array<Line, Rows>;
    struct Coord { size_t x, y; };

    static constexpr size_t rows() { return Rows; }
    static constexpr size_t cols() { return Columns; }

    Screen screen;
    Coord origin;

    BasicCanvas(Coord origin = {Columns/2, Rows/2}) : origin(origin) {
        Line empty;
        std::fill(empty.begin(), empty.end(), '.');
        std::fill(screen.begin(), screen.end(), empty);
    }

    friend std::ostream& operator<<(std::ostream& os, BasicCanvas const& c) {
        for (auto& line : c.screen) {
            os.write(line.data(), line.size()) << "\n";
        }
        return os;
    }

    Line&       operator[](size_t y)          { return screen.at(screen.size()-(y+1)); }
    Line const& operator[](size_t y) const    { return screen.at(screen.size()-(y+1)); }
    char&       operator[](Coord coord)       { return operator[](coord.y).at(coord.x); }
    char const& operator[](Coord coord) const { return operator[](coord.y).at(coord.x); }

    void axes() {
        for (auto& line : screen)
            line.at(origin.x) = '|';

        auto& y_axis = operator[](origin.y);

        for (auto& cell : y_axis)
            cell = '-';

        y_axis.at(origin.x) = '+';
    }

    template <typename F>
    void plot(F f, double scaleX = 1.0, double scaleY = 1.0) {
        for (size_t x_tick = 0; x_tick < Columns; ++x_tick) {
            auto x = (x_tick * scaleX) - origin.x;
            auto y = f(x);
            auto y_ = derivative(f, x, scaleX/2);

            size_t y_tick = (y / scaleY) + origin.y;
            if (y_tick < Rows)
                operator[]({x_tick, y_tick}) = glyph(y_);
        }
    }

  private:
    template <typename F>
    auto derivative(F const& f, double x, double dx = 0.01) {
        return (f(x+dx)-f(x-dx))/(2*dx);
    }

    char glyph(double tangent) {
        auto angle = atan(tangent);

        while (angle < 0) 
            angle += 2*M_PI;

        int angle_index = 2.0 * angle / atan(1);

        return R"(--/||\--)"[angle_index % 8];
    }

};

Full Listing

Live On Coliru

(simplified function selection):

#include <iostream>
#include <array>
#include <cmath>

template <size_t Columns = 100, size_t Rows = 50>
struct BasicCanvas {
    using Line   = std::array<char, Columns>;
    using Screen = std::array<Line, Rows>;
    struct Coord { size_t x, y; };

    static constexpr size_t rows() { return Rows; }
    static constexpr size_t cols() { return Columns; }

    Screen screen;
    Coord origin;

    BasicCanvas(Coord origin = {Columns/2, Rows/2}) : origin(origin) {
        Line empty;
        std::fill(empty.begin(), empty.end(), ' ');
        std::fill(screen.begin(), screen.end(), empty);
    }

    friend std::ostream& operator<<(std::ostream& os, BasicCanvas const& c) {
        for (auto& line : c.screen) {
            os.write(line.data(), line.size()) << "\n";
        }
        return os;
    }

    Line&       operator[](size_t y)          { return screen.at(screen.size()-(y+1)); }
    Line const& operator[](size_t y) const    { return screen.at(screen.size()-(y+1)); }
    char&       operator[](Coord coord)       { return operator[](coord.y).at(coord.x); }
    char const& operator[](Coord coord) const { return operator[](coord.y).at(coord.x); }

    void axes() {
        for (auto& line : screen)
            line.at(origin.x) = '|';

        auto& y_axis = operator[](origin.y);

        for (auto& cell : y_axis)
            cell = '-';

        y_axis.at(origin.x) = '+';
    }

    template <typename F>
    void plot(F f, double scaleX = 1.0, double scaleY = 1.0) {
        for (size_t x_tick = 0; x_tick < Columns; ++x_tick) {
            auto x = (x_tick * scaleX) - origin.x;
            auto y = f(x);
            auto y_ = derivative(f, x, scaleX/2);

            size_t y_tick = (y / scaleY) + origin.y;
            if (y_tick < Rows)
                operator[]({x_tick, y_tick}) = glyph(y_);
        }
    }

  private:
    template <typename F>
    auto derivative(F const& f, double x, double dx = 0.01) {
        return (f(x+dx)-f(x-dx))/(2*dx);
    }

    char glyph(double tangent) {
        auto angle = atan(tangent);

        while (angle < 0) 
            angle += 2*M_PI;

        int angle_index = 2.0 * angle / atan(1);

        return R"(--/||\--)"[angle_index % 8];
    }

};

int main() {
    using Canvas = BasicCanvas<60, 30>;
    Canvas canvas;
    //canvas.origin = {canvas.cols()/3, canvas.rows()/3};

    canvas.axes();

    canvas.plot([](double x) { return  x; });
    //canvas.plot([](double  ) { return -8; });
    canvas.plot([](double x) { return 3*log(x); });
    canvas.plot([](double x) { return 4*sin(x/2); });
    //canvas.plot([](double x) { return 24*cos(x/12); });

    std::cout << canvas;
}

Prints

                              |             /               
                              |            /                
                              |           /                 
                              |          /                  
                              |         /                  -
                              |        /           -------- 
                              |       /      ------         
                              |      /   ----               
                              |     / ---                   
                              |    /--                      
                              |   --                        
       ---          --\       | /--          --\         /--
      /   \        /          | /  \        /               
                  /    \      |/                \       /   
-----/-----\------------------/|----\------/----------------
                 /      \    /|                  \     /    
    /       \               //|      \    /                 
\               /        \ /  |          /        \   /     
 --/         \--          --/ |       \--          ---      
                         /    |                             
                        /     |                             
                       /      |                             
                      /       |                             
                     /        |                             
                    /         |                             
                   /          |                             
                  /           |                             
                 /            |                             
                /             |                             
               /              |                             
like image 66
sehe Avatar answered Sep 24 '22 19:09

sehe