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
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;
}
Or commenting out the origin assignment:
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];
}
};
(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
| /
| /
| /
| /
| / -
| / --------
| / ------
| / ----
| / ---
| /--
| --
--- --\ | /-- --\ /--
/ \ / | / \ /
/ \ |/ \ /
-----/-----\------------------/|----\------/----------------
/ \ /| \ /
/ \ //| \ /
\ / \ / | / \ /
--/ \-- --/ | \-- ---
/ |
/ |
/ |
/ |
/ |
/ |
/ |
/ |
/ |
/ |
/ |
I looked at your 'c' question.
If you want to use a terminal and place chars on the screen, find an ansi terminal emulator for your system, and try Ansi_t:
class Ansi_t // use ansi features of gnome-terminal
{
// note: Ubuntu 15.10 gnome-terminal ansi term cursor locations
// are 1-based with origin 1,1 at top left corner
enum ANSI : char { ESC = 27 };
public:
static inline std::string clrscr(void)
{
std::stringstream ss;
ss << static_cast<char>(ESC) << "[H" // home
<< static_cast<char>(ESC) << "[2J"; // clrbos
return(ss.str());
}
// r/c are 0 based------v------v------0 based
static inline std::string gotoRC(int r, int c)
{
std::stringstream ss;
// Note: row/col of GameOfLife_t is 0 based (as in C++)
ss << static_cast<char>(ESC) << "["
<< (r+1) << ';' << (c+1) << 'H';
// xy of ansi terminal is 1 based -------^^--------------^^
return(ss.str());
}
// tbr - add more ansi functions as needed
}; // Ansi_t
Typical usage is"
std::cout << Ansi_t::clrscr() << std::flush; // clears the screen
std::cout << Ansi_t::gotoRC(5, 25) << '*' << std::flush;
// position the cursor, and output a single 'dot':
Now use this to draw a line, etc.
Note - On ubuntu, the terminal emulations typically have a hot key to reduce font size - it is "Ctrl minus" for some terminals. Repeated application can reduce the font size to unreadable, so each character looks more and more like a dot.
I have successfully used Ansi_t for GameOfLife ...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.