Added files.
23
.travis.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
language: cpp
|
||||||
|
compiler:
|
||||||
|
- clang
|
||||||
|
- gcc
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
install:
|
||||||
|
- sudo apt-get -yqq update
|
||||||
|
- sudo apt-get -yqq install cppcheck
|
||||||
|
script:
|
||||||
|
- g++ -Wall -g -fsanitize=address tables.cpp -o gcc_tables
|
||||||
|
- ./gcc_tables
|
||||||
|
- g++ -Wall -g -fsanitize=address graphs.cpp -o gcc_graphs
|
||||||
|
- ./gcc_graphs
|
||||||
|
- clang++ -Wall -g -fsanitize=address tables.cpp -o clang_tables
|
||||||
|
- ./clang_tables
|
||||||
|
- clang++ -Wall -g -fsanitize=address graphs.cpp -o clang_graphs
|
||||||
|
- ./clang_graphs
|
||||||
|
- cppcheck --error-exitcode=1 .
|
554
README.md
@ -1,2 +1,554 @@
|
|||||||
# Tables-and-Graphs
|
[](https://travis-ci.org/tdulcet/Tables-and-Graphs)
|
||||||
|
|
||||||
|
# Tables and Graphs
|
||||||
|
|
||||||
C++ Console Table and Graph/Plot Libraries
|
C++ Console Table and Graph/Plot Libraries
|
||||||
|
|
||||||
|
Copyright © 2018 Teal Dulcet
|
||||||
|
|
||||||
|
These header only libraries use [box-drawing](https://en.wikipedia.org/wiki/Box-drawing_character#Unicode), [Braille](https://en.wikipedia.org/wiki/Braille_Patterns), [fraction](https://en.wikipedia.org/wiki/Number_Forms) and other Unicode characters and [terminal colors and formatting](https://misc.flogisoft.com/bash/tip_colors_and_formatting) to output tables and graphs/plots to the console.
|
||||||
|
|
||||||
|
Please visit [tealdulcet.com](https://www.tealdulcet.com/) to support these libraries and my other software development.
|
||||||
|
|
||||||
|
## Tables
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Complete versions of all of the examples below and more can be found in the [tables.cpp](tables.cpp) file.
|
||||||
|
|
||||||
|
Compile with: `g++ -Wall -g -O3 tables.cpp -o tables`.
|
||||||
|
|
||||||
|
Run with: `./tables`.
|
||||||
|
|
||||||
|
#### Output char array as table
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "tables.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
size_t rows = 5;
|
||||||
|
size_t columns = 5;
|
||||||
|
|
||||||
|
char ***array;
|
||||||
|
|
||||||
|
// Allocate and set array
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
aoptions.headerrow = true;
|
||||||
|
aoptions.headercolumn = true;
|
||||||
|
|
||||||
|
table(rows, columns, array, NULL, NULL, aoptions);
|
||||||
|
|
||||||
|
// Deallocate array
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Table cells can contain [Unicode characters](https://en.wikipedia.org/wiki/List_of_Unicode_characters), but not newlines and tabs.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Output array as table with separate header row and column
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "tables.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
size_t rows = 4;
|
||||||
|
size_t columns = 4;
|
||||||
|
|
||||||
|
const char* headerrow[] = {"Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"};
|
||||||
|
const char* headercolumn[] = {"Header column 2", "Header column 3", "Header column 4", "Header column 5"};
|
||||||
|
|
||||||
|
char ***array;
|
||||||
|
|
||||||
|
// Allocate and set array
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
aoptions.headerrow = true;
|
||||||
|
aoptions.headercolumn = true;
|
||||||
|
|
||||||
|
table(rows, columns, array, headerrow, headercolumn, aoptions);
|
||||||
|
|
||||||
|
// Deallocate array
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Output same as example above.
|
||||||
|
|
||||||
|
#### Output array as table
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "tables.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
size_t rows = 5;
|
||||||
|
size_t columns = 5;
|
||||||
|
|
||||||
|
double **array; // array can be any data type
|
||||||
|
|
||||||
|
// Allocate and set array
|
||||||
|
|
||||||
|
table(rows, columns, array, NULL, NULL, tabledefaultoptions);
|
||||||
|
|
||||||
|
// Deallocate array
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Output sorted array as table
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <algorithm>
|
||||||
|
#include "tables.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int dimensions; // Number of columns
|
||||||
|
int sortdimension; // Column to sort by
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool compare(const T *a, const T *b)
|
||||||
|
{
|
||||||
|
if (a[sortdimension] == b[sortdimension])
|
||||||
|
for (int i = 0; i < dimensions; ++i)
|
||||||
|
if (sortdimension != i and a[i] != b[i])
|
||||||
|
return a[i] < b[i];
|
||||||
|
|
||||||
|
return a[sortdimension] < b[sortdimension];
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
size_t rows = 5;
|
||||||
|
size_t columns = 5;
|
||||||
|
|
||||||
|
int **array; // array can be any data type
|
||||||
|
|
||||||
|
// Allocate and set array
|
||||||
|
|
||||||
|
dimensions = columns;
|
||||||
|
sortdimension = 0;
|
||||||
|
|
||||||
|
sort(array, array + rows, compare<int>);
|
||||||
|
|
||||||
|
table(rows, columns, array, NULL, NULL, tabledefaultoptions);
|
||||||
|
|
||||||
|
// Deallocate array
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Output single function as table
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "tables.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
double afunction(double x)
|
||||||
|
{
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
double xmin = -10;
|
||||||
|
double xmax = 10;
|
||||||
|
double xscl = 2;
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
aoptions.headerrow = true;
|
||||||
|
|
||||||
|
table(xmin, xmax, xscl, afunction, aoptions);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Output multiple functions as table
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <cmath>
|
||||||
|
#include "tables.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
double function1(double x)
|
||||||
|
{
|
||||||
|
return 2 * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
double function2(double x)
|
||||||
|
{
|
||||||
|
return pow(x, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
double xmin = -10;
|
||||||
|
double xmax = 10;
|
||||||
|
double xscl = 2;
|
||||||
|
|
||||||
|
size_t numfunctions = 2;
|
||||||
|
|
||||||
|
// Function parameter and return value can be any data type, as long as they are the same
|
||||||
|
double (*functions[])(double) = {function1, function2};
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
aoptions.headerrow = true;
|
||||||
|
|
||||||
|
table(xmin, xmax, xscl, numfunctions, functions, aoptions);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### Header row
|
||||||
|
|
||||||
|
Option: `headerrow`
|
||||||
|
|
||||||
|
Default value: `false`
|
||||||
|
|
||||||
|
Header rows are bolded and centered.
|
||||||
|
|
||||||
|
#### Header column
|
||||||
|
|
||||||
|
Option: `headercolumn`
|
||||||
|
|
||||||
|
Default value: `false`
|
||||||
|
|
||||||
|
Header columns are bolded and centered.
|
||||||
|
|
||||||
|
#### Table border
|
||||||
|
|
||||||
|
Option: `tableborder`
|
||||||
|
|
||||||
|
Default value: `true`
|
||||||
|
|
||||||
|
#### Cell border
|
||||||
|
|
||||||
|
Option: `cellborder`
|
||||||
|
|
||||||
|
Default value: `false`
|
||||||
|
|
||||||
|
Requires `tableborder` to be `true`.
|
||||||
|
|
||||||
|
#### Cell padding
|
||||||
|
|
||||||
|
Option: `padding`
|
||||||
|
|
||||||
|
Default value: `1`
|
||||||
|
|
||||||
|
#### Alignment
|
||||||
|
|
||||||
|
Option: `alignment`
|
||||||
|
|
||||||
|
Values:
|
||||||
|
|
||||||
|
* `left` (default)
|
||||||
|
* `right`
|
||||||
|
|
||||||
|
#### bool to alpha
|
||||||
|
|
||||||
|
Option: `boolalpha`
|
||||||
|
|
||||||
|
Default value: `false`
|
||||||
|
|
||||||
|
#### Title
|
||||||
|
|
||||||
|
Option: `title`
|
||||||
|
|
||||||
|
Default value: `NULL`
|
||||||
|
|
||||||
|
The title is word wraped based on the current width of the terminal, using [this](https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0) solution. Handles newlines, tabs and [Unicode characters](https://en.wikipedia.org/wiki/List_of_Unicode_characters).
|
||||||
|
|
||||||
|
#### Border style
|
||||||
|
|
||||||
|
Option: `style`
|
||||||
|
|
||||||
|
Values:
|
||||||
|
|
||||||
|
0. ASCII
|
||||||
|
|
||||||
|

|
||||||
|
1. Basic
|
||||||
|
|
||||||
|

|
||||||
|
2. Light (default)
|
||||||
|
|
||||||
|

|
||||||
|
3. Heavy
|
||||||
|
|
||||||
|

|
||||||
|
4. Double
|
||||||
|
|
||||||
|

|
||||||
|
5. Light Dashed
|
||||||
|
|
||||||
|

|
||||||
|
6. Heavy Dashed
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Other C++ Console Tables Libraries
|
||||||
|
|
||||||
|
* [C++ Text Table](https://github.com/haarcuba/cpp-text-table) (must specify every cell individually in there data structure, limited options, no Unicode support, no header row or column support)
|
||||||
|
* [Cpp Console Table](https://github.com/Oradle/CppConsoleTable) (must specify every cell individually in there data structure, no Unicode support, no header row or column support)
|
||||||
|
* [ConsoleTable](https://github.com/766F6964/ConsoleTable) (requires C++11, must specify entire row at once in there data structure, no header column support)
|
||||||
|
|
||||||
|
## Graphs/Plots
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Complete versions of all of the examples below and more can be found in the [graphs.cpp](graphs.cpp) file.
|
||||||
|
|
||||||
|
Compile with: `g++ -Wall -g -O3 graphs.cpp -o graphs`.
|
||||||
|
|
||||||
|
Run with: `./graphs`.
|
||||||
|
|
||||||
|
If `height` is `0`, it will be set to the current height of the terminal (number of rows times four). If `width` is `0`, it will be set to the current width of the terminal (number of columns times two).
|
||||||
|
|
||||||
|
#### Output array as plot
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "graphs.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
size_t height = 160;
|
||||||
|
size_t width = 160;
|
||||||
|
|
||||||
|
long double xmin = -20;
|
||||||
|
long double xmax = 20;
|
||||||
|
long double ymin = -20;
|
||||||
|
long double ymax = 20;
|
||||||
|
|
||||||
|
size_t rows = 10;
|
||||||
|
|
||||||
|
double **array; // array can be any data type, but must have exactly two columns
|
||||||
|
|
||||||
|
// Allocate and set array
|
||||||
|
|
||||||
|
graph(height, width, xmin, xmax, ymin, ymax, rows, array, graphdefaultoptions);
|
||||||
|
|
||||||
|
// Deallocate array
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If `xmin` and `xmax` are both `0`, they will be set to the respective minimum and maximum values of x in the array. If `ymin` and `ymax` are both `0`, they will be set to the respective minimum and maximum values of y in the array.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Output single function as graph
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "graphs.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
double afunction(double x)
|
||||||
|
{
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
size_t height = 160;
|
||||||
|
size_t width = 160;
|
||||||
|
|
||||||
|
long double xmin = -20;
|
||||||
|
long double xmax = 20;
|
||||||
|
long double ymin = -20;
|
||||||
|
long double ymax = 20;
|
||||||
|
|
||||||
|
graph(height, width, xmin, xmax, ymin, ymax, afunction, graphdefaultoptions);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Output multiple functions as graph
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "graphs.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
double function1(double x)
|
||||||
|
{
|
||||||
|
return 2 * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
double function2(double x)
|
||||||
|
{
|
||||||
|
return pow(x, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
size_t height = 160;
|
||||||
|
size_t width = 160;
|
||||||
|
|
||||||
|
long double xmin = -20;
|
||||||
|
long double xmax = 20;
|
||||||
|
long double ymin = -20;
|
||||||
|
long double ymax = 20;
|
||||||
|
|
||||||
|
size_t numfunctions = 2;
|
||||||
|
|
||||||
|
// Function parameter and return value can be any data type, as long as they are the same
|
||||||
|
double (*functions[])(double) = {function1, function2};
|
||||||
|
|
||||||
|
graph(height, width, xmin, xmax, ymin, ymax, numfunctions, functions, graphdefaultoptions);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### Border/Axis
|
||||||
|
|
||||||
|
Option: `border`
|
||||||
|
|
||||||
|
Default value: `true`
|
||||||
|
|
||||||
|
#### Axis labels
|
||||||
|
|
||||||
|
Option: `axislabel`
|
||||||
|
|
||||||
|
Default value: `true`
|
||||||
|
|
||||||
|
Requires `border` to be `true`.
|
||||||
|
|
||||||
|
#### Axis units labels
|
||||||
|
|
||||||
|
Option: `axisunitslabel`
|
||||||
|
|
||||||
|
Default value: `true`
|
||||||
|
|
||||||
|
Requires `border` and `axislabel` to be `true`.
|
||||||
|
|
||||||
|
#### Title
|
||||||
|
|
||||||
|
Option: `title`
|
||||||
|
|
||||||
|
Default value: `NULL`
|
||||||
|
|
||||||
|
The title is word wraped based on the current width of the terminal, using [this](https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0) solution. Handles newlines, tabs and [Unicode characters](https://en.wikipedia.org/wiki/List_of_Unicode_characters).
|
||||||
|
|
||||||
|
#### Axis/Border style
|
||||||
|
|
||||||
|
Option: `style`
|
||||||
|
|
||||||
|
Values:
|
||||||
|
|
||||||
|
0. ASCII
|
||||||
|
|
||||||
|

|
||||||
|
1. Basic
|
||||||
|
|
||||||
|

|
||||||
|
2. Light (default)
|
||||||
|
|
||||||
|

|
||||||
|
3. Heavy
|
||||||
|
|
||||||
|

|
||||||
|
4. Double
|
||||||
|
|
||||||
|

|
||||||
|
5. Light Dashed
|
||||||
|
|
||||||
|

|
||||||
|
6. Heavy Dashed
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Graph/Plot Color
|
||||||
|
|
||||||
|
Option: `color`
|
||||||
|
|
||||||
|
Values:
|
||||||
|
|
||||||
|
0. System default
|
||||||
|
1. Black
|
||||||
|
2. Red (default)
|
||||||
|
3. Green
|
||||||
|
4. Yellow
|
||||||
|
5. Blue
|
||||||
|
6. Cyan
|
||||||
|
7. Light gray
|
||||||
|
8. Dark gray
|
||||||
|
9. Light red
|
||||||
|
10. Light green
|
||||||
|
11. Light yellow
|
||||||
|
12. Light blue
|
||||||
|
13. Light cyan
|
||||||
|
14. White
|
||||||
|
|
||||||
|
See [here](https://misc.flogisoft.com/bash/tip_colors_and_formatting#foreground_text) for examples of the colors.
|
||||||
|
|
||||||
|
Only used for plots and when graphing a single function.
|
||||||
|
|
||||||
|
When graphing multiple functions, colors `2` - `14` are used inorder. Color `0` is used where the functions cross.
|
||||||
|
|
||||||
|
##### Plot
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
##### Graph
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Other C++ Console Graphs/Plots Libraries
|
||||||
|
|
||||||
|
* [C++ terminal plotting library](https://github.com/fbbdev/plot) (requires C++14, based on [UnicodePlots.jl](https://github.com/Evizero/UnicodePlots.jl), no documentation and very difficult to use, although supports animations)
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Pull requests welcome! Ideas for contributions:
|
||||||
|
|
||||||
|
* Add more options
|
||||||
|
* Add an option to print a border around graphs/plots
|
||||||
|
* Add more examples
|
||||||
|
* Improve the performance
|
||||||
|
* Handle newlines, tabs and formatted text in the tables
|
||||||
|
* Handle formatted text in the table and graph/plot titles
|
||||||
|
* Support more graph/plot colors
|
||||||
|
* Support combining colors when functions cross
|
||||||
|
* Support plotting multiple arrays of different sizes
|
||||||
|
* Port to other languages (C, Java, Rust, etc.)
|
||||||
|
141
graphs.cpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
// Teal Dulcet, CS546
|
||||||
|
|
||||||
|
// Compile: g++ -Wall -g -O3 graphs.cpp -o graphs
|
||||||
|
|
||||||
|
// Run: ./graphs
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include "graphs.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
long double afunction(long double x)
|
||||||
|
{
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
long double function1(long double x)
|
||||||
|
{
|
||||||
|
return 2 * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
long double function2(long double x)
|
||||||
|
{
|
||||||
|
return pow(x, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
long double function3(long double x)
|
||||||
|
{
|
||||||
|
return sin(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
long double function4(long double x)
|
||||||
|
{
|
||||||
|
return cos(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
long double function5(long double x)
|
||||||
|
{
|
||||||
|
return tan(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const size_t height = 160;
|
||||||
|
const size_t width = 160;
|
||||||
|
|
||||||
|
const long double xmin = -20;
|
||||||
|
const long double xmax = 20;
|
||||||
|
const long double ymin = -20;
|
||||||
|
const long double ymax = 20;
|
||||||
|
|
||||||
|
const size_t rows = 10;
|
||||||
|
const size_t columns = 2;
|
||||||
|
|
||||||
|
// Output array as plot
|
||||||
|
cout << "\nOutput array as plot\n\n";
|
||||||
|
{
|
||||||
|
long double **array;
|
||||||
|
array = new long double *[rows];
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
array[i] = new long double[columns];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
array[i][j] = i + j; //rand();
|
||||||
|
|
||||||
|
graphoptions aoptions;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
graph(height, width, xmin, xmax, ymin, ymax, rows, array, aoptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
delete[] array[i];
|
||||||
|
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Output single function as graph
|
||||||
|
cout << "\nOutput single function as graph\n\n";
|
||||||
|
{
|
||||||
|
graphoptions aoptions;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
graph(height, width, xmin, xmax, ymin, ymax, afunction, aoptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Output multiple functions as graph
|
||||||
|
cout << "\nOutput multiple functions as graph\n\n";
|
||||||
|
{
|
||||||
|
long double (*functions[])(long double) = {function1, function2};
|
||||||
|
|
||||||
|
graphoptions aoptions;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
graph(height, width, xmin, xmax, ymin, ymax, 2, functions, aoptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const long double xmin = -(2 * M_PI);
|
||||||
|
const long double xmax = 2 * M_PI;
|
||||||
|
const long double ymin = -4;
|
||||||
|
const long double ymax = 4;
|
||||||
|
|
||||||
|
long double (*functions[])(long double) = {function3, function4, function5};
|
||||||
|
|
||||||
|
graphoptions aoptions;
|
||||||
|
aoptions.axisunitslabel = false;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
graph(height, width, xmin, xmax, ymin, ymax, 3, functions, aoptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*aoptions.style = 2;
|
||||||
|
|
||||||
|
for (unsigned int k = 10; k < 300; ++k)
|
||||||
|
{
|
||||||
|
cout << "\e[1;1H" << "\e[2J";
|
||||||
|
|
||||||
|
graph(k, k, xmin, xmax, ymin, ymax, 3, functions, aoptions);
|
||||||
|
|
||||||
|
usleep(200000);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
725
graphs.hpp
Normal file
@ -0,0 +1,725 @@
|
|||||||
|
// Teal Dulcet, CS546
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
#include <cfloat>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cwchar>
|
||||||
|
#include <clocale>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
const char *const styles[][11] = {
|
||||||
|
{"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, //ASCII
|
||||||
|
{"—", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, //Basic
|
||||||
|
{"─", "│", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, //Light
|
||||||
|
{"━", "┃", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"}, //Heavy
|
||||||
|
{"═", "║", "╔", "╦", "╗", "╠", "╬", "╣", "╚", "╩", "╝"}, //Double
|
||||||
|
{"╌", "╎", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, //Light Dashed
|
||||||
|
{"╍", "╏", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"} //Heavy Dashed
|
||||||
|
};
|
||||||
|
// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border
|
||||||
|
|
||||||
|
const char *const colors[] = {"\e[39m", "\e[30m", "\e[31m", "\e[32m", "\e[33m", "\e[34m", "\e[35m", "\e[36m", "\e[37m", "\e[90m", "\e[91m", "\e[92m", "\e[93m", "\e[94m", "\e[95m", "\e[96m", "\e[97m"};
|
||||||
|
|
||||||
|
const char *const dots[] = {"⠀", "⠁", "⠂", "⠃", "⠄", "⠅", "⠆", "⠇", "⠈", "⠉", "⠊", "⠋", "⠌", "⠍", "⠎", "⠏", "⠐", "⠑", "⠒", "⠓", "⠔", "⠕", "⠖", "⠗", "⠘", "⠙", "⠚", "⠛", "⠜", "⠝", "⠞", "⠟", "⠠", "⠡", "⠢", "⠣", "⠤", "⠥", "⠦", "⠧", "⠨", "⠩", "⠪", "⠫", "⠬", "⠭", "⠮", "⠯", "⠰", "⠱", "⠲", "⠳", "⠴", "⠵", "⠶", "⠷", "⠸", "⠹", "⠺", "⠻", "⠼", "⠽", "⠾", "⠿", "⡀", "⡁", "⡂", "⡃", "⡄", "⡅", "⡆", "⡇", "⡈", "⡉", "⡊", "⡋", "⡌", "⡍", "⡎", "⡏", "⡐", "⡑", "⡒", "⡓", "⡔", "⡕", "⡖", "⡗", "⡘", "⡙", "⡚", "⡛", "⡜", "⡝", "⡞", "⡟", "⡠", "⡡", "⡢", "⡣", "⡤", "⡥", "⡦", "⡧", "⡨", "⡩", "⡪", "⡫", "⡬", "⡭", "⡮", "⡯", "⡰", "⡱", "⡲", "⡳", "⡴", "⡵", "⡶", "⡷", "⡸", "⡹", "⡺", "⡻", "⡼", "⡽", "⡾", "⡿", "⢀", "⢁", "⢂", "⢃", "⢄", "⢅", "⢆", "⢇", "⢈", "⢉", "⢊", "⢋", "⢌", "⢍", "⢎", "⢏", "⢐", "⢑", "⢒", "⢓", "⢔", "⢕", "⢖", "⢗", "⢘", "⢙", "⢚", "⢛", "⢜", "⢝", "⢞", "⢟", "⢠", "⢡", "⢢", "⢣", "⢤", "⢥", "⢦", "⢧", "⢨", "⢩", "⢪", "⢫", "⢬", "⢭", "⢮", "⢯", "⢰", "⢱", "⢲", "⢳", "⢴", "⢵", "⢶", "⢷", "⢸", "⢹", "⢺", "⢻", "⢼", "⢽", "⢾", "⢿", "⣀", "⣁", "⣂", "⣃", "⣄", "⣅", "⣆", "⣇", "⣈", "⣉", "⣊", "⣋", "⣌", "⣍", "⣎", "⣏", "⣐", "⣑", "⣒", "⣓", "⣔", "⣕", "⣖", "⣗", "⣘", "⣙", "⣚", "⣛", "⣜", "⣝", "⣞", "⣟", "⣠", "⣡", "⣢", "⣣", "⣤", "⣥", "⣦", "⣧", "⣨", "⣩", "⣪", "⣫", "⣬", "⣭", "⣮", "⣯", "⣰", "⣱", "⣲", "⣳", "⣴", "⣵", "⣶", "⣷", "⣸", "⣹", "⣺", "⣻", "⣼", "⣽", "⣾", "⣿"};
|
||||||
|
|
||||||
|
const int values[][4] = {{0x1, 0x2, 0x4, 0x40}, {0x8, 0x10, 0x20, 0x80}};
|
||||||
|
|
||||||
|
const char *const fractions[] = {"¼", "½", "¾", "⅐", "⅑", "⅒", "⅓", "⅔", "⅕", "⅖", "⅗", "⅘", "⅙", "⅚", "⅛", "⅜", "⅝", "⅞"};
|
||||||
|
|
||||||
|
const long double fractionvalues[] = {1.0L / 4.0L, 1.0L / 2.0L, 3.0L / 4.0L, 1.0L / 7.0L, 1.0L / 9.0L, 1.0L / 10.0L, 1.0L / 3.0L, 2.0L / 3.0L, 1.0L / 5.0L, 2.0L / 5.0L, 3.0L / 5.0L, 4.0L / 5.0L, 1.0L / 6.0L, 5.0L / 6.0L, 1.0L / 8.0L, 3.0L / 8.0L, 5.0L / 8.0L, 7.0L / 8.0L};
|
||||||
|
|
||||||
|
struct graphoptions
|
||||||
|
{
|
||||||
|
bool border;
|
||||||
|
bool axislabel;
|
||||||
|
bool axisunitslabel;
|
||||||
|
char *title;
|
||||||
|
unsigned int style;
|
||||||
|
unsigned int color;
|
||||||
|
graphoptions(void);
|
||||||
|
~graphoptions(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
graphoptions::graphoptions(void)
|
||||||
|
{
|
||||||
|
border = true;
|
||||||
|
axislabel = true;
|
||||||
|
axisunitslabel = true;
|
||||||
|
style = 2;
|
||||||
|
color = 2;
|
||||||
|
title = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
graphoptions::~graphoptions(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const graphoptions graphdefaultoptions;
|
||||||
|
|
||||||
|
// Number of columns needed to represent the string
|
||||||
|
// Adapted from: https://stackoverflow.com/a/31124065
|
||||||
|
int strcol(const char *const str)
|
||||||
|
{
|
||||||
|
size_t length = strlen(str);
|
||||||
|
for (size_t i = 0; i < length; ++i)
|
||||||
|
if (iscntrl(str[i]))
|
||||||
|
{
|
||||||
|
cerr << "\nError! Control character in string.\n";
|
||||||
|
cout << "Control character: " << (int)str[i] << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
length = mbstowcs(NULL, str, 0);
|
||||||
|
if (length == (size_t)-1)
|
||||||
|
{
|
||||||
|
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
++length;
|
||||||
|
|
||||||
|
wchar_t *wcstring = new wchar_t[length];
|
||||||
|
|
||||||
|
if (mbstowcs(wcstring, str, length) == (size_t)-1)
|
||||||
|
{
|
||||||
|
if (wcstring != NULL)
|
||||||
|
delete[] wcstring;
|
||||||
|
|
||||||
|
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = wcswidth(wcstring, length);
|
||||||
|
if (width == -1)
|
||||||
|
{
|
||||||
|
cerr << "\nError! wcswidth failed. Nonprintable wide character.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcstring != NULL)
|
||||||
|
delete[] wcstring;
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word wrap
|
||||||
|
// Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0
|
||||||
|
// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734
|
||||||
|
string wrap(const char *const str, const size_t line_length)
|
||||||
|
{
|
||||||
|
char words[strlen(str) + 1];
|
||||||
|
strcpy(words, str);
|
||||||
|
string wrapped;
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
size_t linelen = 0;
|
||||||
|
while (words[index] != '\0')
|
||||||
|
{
|
||||||
|
if (words[index] == '\n')
|
||||||
|
{
|
||||||
|
linelen = 0;
|
||||||
|
}
|
||||||
|
else if (isspace(words[index]))
|
||||||
|
{
|
||||||
|
size_t tempindex = index + 1;
|
||||||
|
size_t templinelen = linelen;
|
||||||
|
while (!isspace(words[tempindex]) and words[tempindex] != '\0')
|
||||||
|
{
|
||||||
|
++templinelen;
|
||||||
|
|
||||||
|
++tempindex;
|
||||||
|
}
|
||||||
|
|
||||||
|
char temp[templinelen + 1];
|
||||||
|
strncpy(temp, words + (index - linelen), templinelen);
|
||||||
|
temp[templinelen] = '\0';
|
||||||
|
|
||||||
|
size_t width = strcol(temp);
|
||||||
|
|
||||||
|
if (width >= line_length)
|
||||||
|
{
|
||||||
|
words[index] = '\n';
|
||||||
|
linelen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (words[index] == '\t')
|
||||||
|
linelen += 8 - (linelen % 8);
|
||||||
|
else if (words[index] != '\n')
|
||||||
|
++linelen;
|
||||||
|
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
wrapped = words;
|
||||||
|
return wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert fractions and constants to Unicode characters
|
||||||
|
size_t outputlabel(const long double label, ostringstream &strm)
|
||||||
|
{
|
||||||
|
bool output = false;
|
||||||
|
|
||||||
|
long double intpart = 0;
|
||||||
|
long double fractionpart = abs(modf(label, &intpart));
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < (sizeof fractions / sizeof fractions[0]) and !output; ++i)
|
||||||
|
{
|
||||||
|
if (abs(fractionpart - fractionvalues[i]) < DBL_EPSILON)
|
||||||
|
{
|
||||||
|
if (intpart != 0)
|
||||||
|
strm << intpart;
|
||||||
|
|
||||||
|
strm << fractions[i];
|
||||||
|
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output and fmod(label, M_PI) == 0)
|
||||||
|
{
|
||||||
|
const char symbol[] = "π";
|
||||||
|
|
||||||
|
intpart = label / M_PI;
|
||||||
|
|
||||||
|
if (intpart == -1)
|
||||||
|
strm << "-";
|
||||||
|
else if (intpart != 1)
|
||||||
|
strm << intpart;
|
||||||
|
|
||||||
|
strm << symbol;
|
||||||
|
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
else if (!output and fmod(label, M_E) == 0)
|
||||||
|
{
|
||||||
|
const char symbol[] = "e";
|
||||||
|
|
||||||
|
intpart = label / M_E;
|
||||||
|
|
||||||
|
if (intpart == -1)
|
||||||
|
strm << "-";
|
||||||
|
else if (intpart != 1)
|
||||||
|
strm << intpart;
|
||||||
|
|
||||||
|
strm << symbol;
|
||||||
|
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output)
|
||||||
|
strm << label;
|
||||||
|
|
||||||
|
size_t length = strcol(strm.str().c_str());
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output graph
|
||||||
|
int graph(const size_t height, const size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, unsigned short **array, const graphoptions &aoptions)
|
||||||
|
{
|
||||||
|
if (array == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
const bool border = aoptions.border;
|
||||||
|
const bool axislabel = aoptions.axislabel;
|
||||||
|
const bool axisunitslabel = aoptions.axisunitslabel;
|
||||||
|
const char *const title = aoptions.title;
|
||||||
|
const unsigned int style = aoptions.style;
|
||||||
|
|
||||||
|
if (style >= (sizeof styles / sizeof styles[0]))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (height == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (width == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
struct winsize w;
|
||||||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
|
|
||||||
|
const int aheight = height / 4;
|
||||||
|
const int awidth = width / 2;
|
||||||
|
|
||||||
|
if (aheight > w.ws_row)
|
||||||
|
{
|
||||||
|
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (awidth > w.ws_col)
|
||||||
|
{
|
||||||
|
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmin >= xmax)
|
||||||
|
{
|
||||||
|
cerr << "xmin must be less than xmax.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ymin >= ymax)
|
||||||
|
{
|
||||||
|
cerr << "ymin must be less than ymax.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const long double xscl = width / (xmax - xmin);
|
||||||
|
const long double yscl = height / (ymax - ymin);
|
||||||
|
const long double xaxis = width - (xmax * xscl);
|
||||||
|
const long double yaxis = ymax * yscl;
|
||||||
|
const int divisor = 2 * 4 * ((width / 160.0) > 1 ? (width / 160) + 1 : 1);
|
||||||
|
|
||||||
|
setlocale(LC_CTYPE, "");
|
||||||
|
|
||||||
|
if (title != NULL and title[0] != '\0')
|
||||||
|
cout << wrap(title, w.ws_col) << "\n";
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < height; i += 4)
|
||||||
|
{
|
||||||
|
const bool ayaxis = (i <= yaxis and (i + 4) > yaxis);
|
||||||
|
const bool yaxislabel = (i <= (yaxis + 4) and (i + 4) > (yaxis + 4));
|
||||||
|
|
||||||
|
ostringstream ylabelstrm;
|
||||||
|
size_t ylabellength = 0;
|
||||||
|
|
||||||
|
if (border and axislabel and axisunitslabel)
|
||||||
|
{
|
||||||
|
bool output = false;
|
||||||
|
long double label;
|
||||||
|
int adivisor = divisor;
|
||||||
|
if (i < yaxis)
|
||||||
|
adivisor = -adivisor;
|
||||||
|
|
||||||
|
for (long double k = yaxis + adivisor; ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and (i >= 4 or !axislabel) and !output; k += adivisor)
|
||||||
|
{
|
||||||
|
if (i <= k and (i + 4) > k)
|
||||||
|
{
|
||||||
|
label = ymax - (k / yscl);
|
||||||
|
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output)
|
||||||
|
{
|
||||||
|
ylabellength = outputlabel(label, ylabelstrm);
|
||||||
|
ylabellength *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < width; j += 2)
|
||||||
|
{
|
||||||
|
const bool axaxis = (j <= xaxis and (j + 2) > xaxis);
|
||||||
|
const bool xaxislabel = (j <= (xaxis - 2) and (j + 2) > (xaxis - 2));
|
||||||
|
|
||||||
|
bool output = false;
|
||||||
|
|
||||||
|
if (border)
|
||||||
|
{
|
||||||
|
if (axaxis and ayaxis)
|
||||||
|
{
|
||||||
|
cout << styles[style][6];
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
else if (axaxis)
|
||||||
|
{
|
||||||
|
if (axisunitslabel)
|
||||||
|
{
|
||||||
|
int adivisor = divisor;
|
||||||
|
if (i < yaxis)
|
||||||
|
adivisor = -adivisor;
|
||||||
|
|
||||||
|
for (long double k = yaxis + adivisor; ((i < yaxis and k >= i) or (i > yaxis and k < (i + 4))) and (i >= 4 or !axislabel) and !output; k += adivisor)
|
||||||
|
{
|
||||||
|
if (i <= k and (i + 4) > k)
|
||||||
|
{
|
||||||
|
cout << styles[style][7];
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
cout << styles[style][4];
|
||||||
|
else if (i >= (height - 4))
|
||||||
|
cout << styles[style][10];
|
||||||
|
else
|
||||||
|
cout << styles[style][1];
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ayaxis)
|
||||||
|
{
|
||||||
|
if (axisunitslabel)
|
||||||
|
{
|
||||||
|
int adivisor = divisor;
|
||||||
|
if (j < xaxis)
|
||||||
|
adivisor = -adivisor;
|
||||||
|
|
||||||
|
for (long double k = xaxis + adivisor; ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and (j < (width - 4) or !axislabel) and !output; k += adivisor)
|
||||||
|
{
|
||||||
|
if (j <= k and (j + 2) > k)
|
||||||
|
{
|
||||||
|
cout << styles[style][3];
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
if (j == 0)
|
||||||
|
cout << styles[style][2];
|
||||||
|
else if (j >= (width - 2))
|
||||||
|
cout << styles[style][4];
|
||||||
|
else
|
||||||
|
cout << styles[style][0];
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (yaxislabel and xaxislabel and axisunitslabel)
|
||||||
|
{
|
||||||
|
cout << "0";
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
else if (j >= (width - 2) and yaxislabel and axislabel)
|
||||||
|
{
|
||||||
|
cout << "x";
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
else if (yaxislabel and axislabel and axisunitslabel)
|
||||||
|
{
|
||||||
|
long double label;
|
||||||
|
int adivisor = divisor;
|
||||||
|
if (j < xaxis)
|
||||||
|
{
|
||||||
|
adivisor = -adivisor;
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (long double k = xaxis + adivisor; ((j < xaxis and k >= j) or (j > xaxis and k < (j + 2))) and j < (width - 2) and !output; k += adivisor)
|
||||||
|
{
|
||||||
|
if (j <= k and (j + 2) > k)
|
||||||
|
{
|
||||||
|
label = (k / xscl) + xmin;
|
||||||
|
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adivisor < 0)
|
||||||
|
j -= 2;
|
||||||
|
|
||||||
|
if (output)
|
||||||
|
{
|
||||||
|
output = false;
|
||||||
|
|
||||||
|
ostringstream strm;
|
||||||
|
size_t length = outputlabel(label, strm);
|
||||||
|
length *= 2;
|
||||||
|
if ((j >= xaxis or (j + length) < (xaxis - 4)) and (j + length) < (width - 2))
|
||||||
|
{
|
||||||
|
cout << strm.str();
|
||||||
|
|
||||||
|
if (length > 2)
|
||||||
|
j += length - 2;
|
||||||
|
|
||||||
|
if (adivisor < 0)
|
||||||
|
output = true;
|
||||||
|
else
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (i == 0 and xaxislabel and axislabel)
|
||||||
|
{
|
||||||
|
cout << "y";
|
||||||
|
output = true;
|
||||||
|
}
|
||||||
|
else if ((j <= (xaxis - ylabellength) and (j + 2) > (xaxis - ylabellength)) and axislabel and axisunitslabel)
|
||||||
|
{
|
||||||
|
cout << ylabelstrm.str();
|
||||||
|
output = true;
|
||||||
|
if (ylabellength > 2)
|
||||||
|
j += ylabellength - 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
unsigned int dot = 0;
|
||||||
|
unsigned short color = 0;
|
||||||
|
|
||||||
|
for (int k = 0; k < 2 and (j + k) < width; ++k)
|
||||||
|
{
|
||||||
|
for (int l = 0; l < 4 and (i + l) < height; ++l)
|
||||||
|
{
|
||||||
|
dot += (array[j + k][i + l] ? 1 : 0) * values[k][l];
|
||||||
|
if (color)
|
||||||
|
{
|
||||||
|
if (array[j + k][i + l] and color != array[j + k][i + l])
|
||||||
|
color = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
color = array[j + k][i + l];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color)
|
||||||
|
--color;
|
||||||
|
|
||||||
|
if (color)
|
||||||
|
cout << colors[color];
|
||||||
|
|
||||||
|
cout << "\e[1m" << dots[dot] << "\e[22m";
|
||||||
|
|
||||||
|
if (color)
|
||||||
|
cout << colors[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert array to graph and output
|
||||||
|
template <typename T>
|
||||||
|
int graph(size_t height, size_t width, long double xmin, long double xmax, long double ymin, long double ymax, const size_t rows, T **array, const graphoptions &aoptions)
|
||||||
|
{
|
||||||
|
if (rows == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (array == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
const unsigned int color = aoptions.color;
|
||||||
|
|
||||||
|
if (color >= (sizeof colors / sizeof colors[0]))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
struct winsize w;
|
||||||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
|
|
||||||
|
if (height == 0)
|
||||||
|
height = w.ws_row * 4;
|
||||||
|
|
||||||
|
if (width == 0)
|
||||||
|
width = w.ws_col * 2;
|
||||||
|
|
||||||
|
const int aheight = height / 4;
|
||||||
|
const int awidth = width / 2;
|
||||||
|
|
||||||
|
if (aheight > w.ws_row)
|
||||||
|
{
|
||||||
|
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (awidth > w.ws_col)
|
||||||
|
{
|
||||||
|
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmin == 0 and xmax == 0)
|
||||||
|
{
|
||||||
|
xmin = numeric_limits<T>::max();
|
||||||
|
xmax = numeric_limits<T>::min();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
if (array[i][0] < xmin)
|
||||||
|
xmin = array[i][0];
|
||||||
|
|
||||||
|
if (array[i][0] > xmax)
|
||||||
|
xmax = array[i][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ymin == 0 and ymax == 0)
|
||||||
|
{
|
||||||
|
ymin = numeric_limits<T>::max();
|
||||||
|
ymax = numeric_limits<T>::min();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
if (array[i][1] < ymin)
|
||||||
|
ymin = array[i][1];
|
||||||
|
|
||||||
|
if (array[i][1] > ymax)
|
||||||
|
ymax = array[i][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmin >= xmax)
|
||||||
|
{
|
||||||
|
cerr << "xmin must be less than xmax.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ymin >= ymax)
|
||||||
|
{
|
||||||
|
cerr << "ymin must be less than ymax.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const long double xscl = width / (xmax - xmin);
|
||||||
|
const long double yscl = height / (ymax - ymin);
|
||||||
|
const long double xaxis = width - (xmax * xscl);
|
||||||
|
const long double yaxis = ymax * yscl;
|
||||||
|
|
||||||
|
unsigned short **aarray;
|
||||||
|
aarray = new unsigned short *[width];
|
||||||
|
for (unsigned int i = 0; i < width; ++i)
|
||||||
|
aarray[i] = new unsigned short[height];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < width; ++i)
|
||||||
|
for (unsigned int j = 0; j < height; ++j)
|
||||||
|
aarray[i][j] = 0;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
if (array[i][0] >= xmin and array[i][0] < xmax and array[i][1] >= ymin and array[i][1] < ymax)
|
||||||
|
{
|
||||||
|
const long long x = (array[i][0] * xscl) + xaxis;
|
||||||
|
const long long y = (yaxis - (array[i][1] * yscl)) - 1;
|
||||||
|
|
||||||
|
aarray[x][y] = color + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int code = graph(height, width, xmin, xmax, ymin, ymax, aarray, aoptions);
|
||||||
|
|
||||||
|
if (aarray != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < width; ++i)
|
||||||
|
delete[] aarray[i];
|
||||||
|
|
||||||
|
delete[] aarray;
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert one or more functions to graph and output
|
||||||
|
template <typename T>
|
||||||
|
int graph(size_t height, size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, const size_t numfunctions, T (*functions[])(T), const graphoptions &aoptions)
|
||||||
|
{
|
||||||
|
const unsigned int color = aoptions.color;
|
||||||
|
|
||||||
|
if (color >= (sizeof colors / sizeof colors[0]))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (numfunctions == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
struct winsize w;
|
||||||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
|
|
||||||
|
if (height == 0)
|
||||||
|
height = w.ws_row * 4;
|
||||||
|
|
||||||
|
if (width == 0)
|
||||||
|
width = w.ws_col * 2;
|
||||||
|
|
||||||
|
const int aheight = height / 4;
|
||||||
|
const int awidth = width / 2;
|
||||||
|
|
||||||
|
if (aheight > w.ws_row)
|
||||||
|
{
|
||||||
|
cerr << "The height of the graph (" << aheight << ") is greater then the height of the terminal (" << w.ws_row << ").\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (awidth > w.ws_col)
|
||||||
|
{
|
||||||
|
cerr << "The width of the graph (" << awidth << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmin >= xmax)
|
||||||
|
{
|
||||||
|
cerr << "xmin must be less than xmax.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ymin >= ymax)
|
||||||
|
{
|
||||||
|
cerr << "ymin must be less than ymax.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t rows = width;
|
||||||
|
|
||||||
|
const long double xscl = width / (xmax - xmin);
|
||||||
|
const long double yscl = height / (ymax - ymin);
|
||||||
|
const long double xaxis = width - (xmax * xscl);
|
||||||
|
const long double yaxis = ymax * yscl;
|
||||||
|
|
||||||
|
unsigned short **array;
|
||||||
|
array = new unsigned short *[width];
|
||||||
|
for (unsigned int i = 0; i < width; ++i)
|
||||||
|
array[i] = new unsigned short[height];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < width; ++i)
|
||||||
|
for (unsigned int j = 0; j < height; ++j)
|
||||||
|
array[i][j] = 0;
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < numfunctions; ++j)
|
||||||
|
{
|
||||||
|
unsigned short acolor = numfunctions == 1 ? color + 1 : (j % ((sizeof colors / sizeof colors[0]) - 2)) + 3;
|
||||||
|
|
||||||
|
for (long double i = 0; i < rows; i += 0.5)
|
||||||
|
{
|
||||||
|
T x = (i / xscl) + xmin;
|
||||||
|
T y = (functions[j])(x);
|
||||||
|
|
||||||
|
if (x >= xmin and x < xmax and y >= ymin and y < ymax)
|
||||||
|
{
|
||||||
|
const long long ax = (x * xscl) + xaxis;
|
||||||
|
const long long ay = (yaxis - (y * yscl)) - 1;
|
||||||
|
|
||||||
|
if (array[ax][ay])
|
||||||
|
{
|
||||||
|
if (array[ax][ay] != acolor)
|
||||||
|
array[ax][ay] = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
array[ax][ay] = acolor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int code = graph(height, width, xmin, xmax, ymin, ymax, array, aoptions);
|
||||||
|
|
||||||
|
if (array != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < width; ++i)
|
||||||
|
delete[] array[i];
|
||||||
|
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert single function to function array and output
|
||||||
|
template <typename T>
|
||||||
|
int graph(size_t height, size_t width, const long double xmin, const long double xmax, const long double ymin, const long double ymax, T afunction(T), const graphoptions &aoptions)
|
||||||
|
{
|
||||||
|
T(*functions[])
|
||||||
|
(T) = {afunction};
|
||||||
|
|
||||||
|
return graph(height, width, xmin, xmax, ymin, ymax, 1, functions, aoptions);
|
||||||
|
}
|
BIN
images/ASCII graph.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
images/ASCII table.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
images/array to plot.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
images/array to table.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
images/basic graph.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
images/basic table.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
images/char array to table.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
images/double graph.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
images/double table.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
images/function to graph.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
images/function to table.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
images/graph colors.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
images/heavy dashed graph.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
images/heavy dashed table.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
images/heavy graph.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
images/heavy table.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
images/light dashed graph.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
images/light dashed table.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
images/light graph.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
images/light table.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
images/multiple functions to graph.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
images/multiple functions to table.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
images/plot colors.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
images/sorted array to table.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
329
tables.cpp
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
// Teal Dulcet, CS546
|
||||||
|
|
||||||
|
// Compile: g++ -Wall -g -O3 tables.cpp -o tables
|
||||||
|
|
||||||
|
// Run: ./tables
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
// #include <cstdlib>
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "tables.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
long double afunction(long double x)
|
||||||
|
{
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
long double function1(long double x)
|
||||||
|
{
|
||||||
|
return 2 * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
long double function2(long double x)
|
||||||
|
{
|
||||||
|
return pow(x, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dimensions = 0;
|
||||||
|
int sortdimension = 0;
|
||||||
|
|
||||||
|
/* template <typename T>
|
||||||
|
int compare(const void *pa, const void *pb)
|
||||||
|
{
|
||||||
|
const T *a = *(const T **)pa;
|
||||||
|
const T *b = *(const T **)pb;
|
||||||
|
|
||||||
|
if (a[sortdimension] == b[sortdimension])
|
||||||
|
{
|
||||||
|
for (int i = 0; i < dimensions; ++i)
|
||||||
|
{
|
||||||
|
if (sortdimension != i and a[i] != b[i])
|
||||||
|
{
|
||||||
|
if (a[i] > b[i])
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a[sortdimension] > b[sortdimension])
|
||||||
|
return 1;
|
||||||
|
else if (a[sortdimension] == b[sortdimension])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
} */
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool compare(const T *a, const T *b)
|
||||||
|
{
|
||||||
|
if (a[sortdimension] == b[sortdimension])
|
||||||
|
for (int i = 0; i < dimensions; ++i)
|
||||||
|
if (sortdimension != i and a[i] != b[i])
|
||||||
|
return a[i] < b[i];
|
||||||
|
|
||||||
|
return a[sortdimension] < b[sortdimension];
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const size_t rows = 5;
|
||||||
|
const size_t columns = 5;
|
||||||
|
|
||||||
|
const long double xmin = -10;
|
||||||
|
const long double xmax = 10;
|
||||||
|
const long double xscl = 2; // 80 / (xmax - xmin);
|
||||||
|
|
||||||
|
// Output array as table
|
||||||
|
cout << "\nOutput array as table\n\n";
|
||||||
|
{
|
||||||
|
long long **array;
|
||||||
|
array = new long long *[rows];
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
array[i] = new long long[columns];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
array[i][j] = rand();
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
table(rows, columns, array, NULL, NULL, aoptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
delete[] array[i];
|
||||||
|
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
long double **array;
|
||||||
|
array = new long double *[rows];
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
array[i] = new long double[columns];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
array[i][j] = static_cast<long double>(rand()) / static_cast<long double>(RAND_MAX);
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
table(rows, columns, array, NULL, NULL, aoptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
delete[] array[i];
|
||||||
|
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Output char array as table
|
||||||
|
cout << "\nOutput char array as table\n\n";
|
||||||
|
{
|
||||||
|
const char *const aarray[rows][columns] = {
|
||||||
|
{"Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"},
|
||||||
|
{"Header column 2", "Data 1", "Data 2", "Data 3", "Data 4"},
|
||||||
|
{"Header column 3", "Data 5", "Data 6", "Data 7", "Data 8"},
|
||||||
|
{"Header column 4", "Data 9", "Data 10", "Data 11", "Data 12"},
|
||||||
|
{"Header column 5", "Data 13", "Data 14", "Data 15", "Data 16"}};
|
||||||
|
|
||||||
|
char ***array;
|
||||||
|
array = new char **[rows];
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
array[i] = new char *[columns];
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
array[i][j] = new char[strlen(aarray[i][j]) + 1];
|
||||||
|
strcpy(array[i][j], aarray[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
aoptions.headerrow = true;
|
||||||
|
aoptions.headercolumn = true;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
table(rows, columns, array, NULL, NULL, aoptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
delete[] array[i][j];
|
||||||
|
|
||||||
|
delete[] array[i];
|
||||||
|
}
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Output array as table with separate header row and column
|
||||||
|
cout << "\nOutput array as table with separate header row and column\n\n";
|
||||||
|
{
|
||||||
|
const size_t rows = 4;
|
||||||
|
const size_t columns = 4;
|
||||||
|
|
||||||
|
const char *const aarray[rows][columns] = {
|
||||||
|
{"Data 1", "Data 2", "Data 3", "Data 4"},
|
||||||
|
{"Data 5", "Data 6", "Data 7", "Data 8"},
|
||||||
|
{"Data 9", "Data 10", "Data 11", "Data 12"},
|
||||||
|
{"Data 13", "Data 14", "Data 15", "Data 16"}};
|
||||||
|
|
||||||
|
const char *const headerrow[] = {"Header row/column 1", "Header row 2", "Header row 3", "Header row 4", "Header row 5"};
|
||||||
|
const char *const headercolumn[] = {"Header column 2", "Header column 3", "Header column 4", "Header column 5"};
|
||||||
|
|
||||||
|
char ***array;
|
||||||
|
array = new char **[rows];
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
array[i] = new char *[columns];
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
array[i][j] = new char[strlen(aarray[i][j]) + 1];
|
||||||
|
strcpy(array[i][j], aarray[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
aoptions.headerrow = true;
|
||||||
|
aoptions.headercolumn = true;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
table(rows, columns, array, headerrow, headercolumn, aoptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
delete[] array[i][j];
|
||||||
|
|
||||||
|
delete[] array[i];
|
||||||
|
}
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
bool **array;
|
||||||
|
array = new bool *[rows];
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
array[i] = new bool[columns];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
array[i][j] = rand() % 2;
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
aoptions.boolalpha = true;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
table(rows, columns, array, NULL, NULL, aoptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
delete[] array[i];
|
||||||
|
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Output sorted array as table
|
||||||
|
cout << "\nOutput sorted array as table\n\n";
|
||||||
|
{
|
||||||
|
int **array;
|
||||||
|
array = new int *[rows];
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
array[i] = new int[columns];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
array[i][j] = rand();
|
||||||
|
|
||||||
|
dimensions = columns;
|
||||||
|
sortdimension = 0;
|
||||||
|
|
||||||
|
// qsort(array, rows, sizeof(array[0]), compare<int>);
|
||||||
|
sort(array, array + rows, compare<int>);
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
table(rows, columns, array, NULL, NULL, aoptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
delete[] array[i];
|
||||||
|
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Output single function as table
|
||||||
|
cout << "\nOutput single function as table\n\n";
|
||||||
|
{
|
||||||
|
tableoptions aoptions;
|
||||||
|
aoptions.headerrow = true;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
table(xmin, xmax, xscl, afunction, aoptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Output multiple functions as table
|
||||||
|
cout << "\nOutput multiple functions as table\n\n";
|
||||||
|
{
|
||||||
|
long double (*functions[])(long double) = {function1, function2};
|
||||||
|
|
||||||
|
tableoptions aoptions;
|
||||||
|
aoptions.headerrow = true;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < (sizeof styles / sizeof styles[0]); ++k)
|
||||||
|
{
|
||||||
|
aoptions.style = k;
|
||||||
|
|
||||||
|
table(xmin, xmax, xscl, 2, functions, aoptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
519
tables.hpp
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
// Teal Dulcet, CS546
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cwchar>
|
||||||
|
#include <clocale>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
const char *const styles[][11] = {
|
||||||
|
{"-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, //ASCII
|
||||||
|
{"—", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+"}, //Basic
|
||||||
|
{"─", "│", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, //Light
|
||||||
|
{"━", "┃", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"}, //Heavy
|
||||||
|
{"═", "║", "╔", "╦", "╗", "╠", "╬", "╣", "╚", "╩", "╝"}, //Double
|
||||||
|
{"╌", "╎", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"}, //Light Dashed
|
||||||
|
{"╍", "╏", "┏", "┳", "┓", "┣", "╋", "┫", "┗", "┻", "┛"} //Heavy Dashed
|
||||||
|
};
|
||||||
|
// {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}};//No border
|
||||||
|
|
||||||
|
struct tableoptions
|
||||||
|
{
|
||||||
|
bool headerrow;
|
||||||
|
bool headercolumn;
|
||||||
|
bool tableborder;
|
||||||
|
bool cellborder;
|
||||||
|
unsigned int padding;
|
||||||
|
ios_base &(*alignment)(ios_base &);
|
||||||
|
bool boolalpha;
|
||||||
|
char *title;
|
||||||
|
unsigned int style;
|
||||||
|
tableoptions(void);
|
||||||
|
~tableoptions(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
tableoptions::tableoptions(void)
|
||||||
|
{
|
||||||
|
headerrow = false;
|
||||||
|
headercolumn = false;
|
||||||
|
tableborder = true;
|
||||||
|
cellborder = false;
|
||||||
|
padding = 1;
|
||||||
|
alignment = left;
|
||||||
|
boolalpha = false;
|
||||||
|
title = NULL;
|
||||||
|
style = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
tableoptions::~tableoptions(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableoptions tabledefaultoptions;
|
||||||
|
|
||||||
|
// Number of columns needed to represent the string
|
||||||
|
// Adapted from: https://stackoverflow.com/a/31124065
|
||||||
|
int strcol(const char *const str)
|
||||||
|
{
|
||||||
|
size_t length = strlen(str);
|
||||||
|
for (size_t i = 0; i < length; ++i)
|
||||||
|
if (iscntrl(str[i]))
|
||||||
|
{
|
||||||
|
cerr << "\nError! Control character in string.\n";
|
||||||
|
cout << "Control character: " << (int)str[i] << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
length = mbstowcs(NULL, str, 0);
|
||||||
|
if (length == (size_t)-1)
|
||||||
|
{
|
||||||
|
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
++length;
|
||||||
|
|
||||||
|
wchar_t *wcstring = new wchar_t[length];
|
||||||
|
|
||||||
|
if (mbstowcs(wcstring, str, length) == (size_t)-1)
|
||||||
|
{
|
||||||
|
if (wcstring != NULL)
|
||||||
|
delete[] wcstring;
|
||||||
|
|
||||||
|
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = wcswidth(wcstring, length);
|
||||||
|
if (width == -1)
|
||||||
|
{
|
||||||
|
cerr << "\nError! wcswidth failed. Nonprintable wide character.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcstring != NULL)
|
||||||
|
delete[] wcstring;
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word wrap
|
||||||
|
// Source: https://gist.github.com/tdulcet/819821ca69501822ad3f84a060c640a0
|
||||||
|
// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734
|
||||||
|
string wrap(const char *const str, const size_t line_length)
|
||||||
|
{
|
||||||
|
char words[strlen(str) + 1];
|
||||||
|
strcpy(words, str);
|
||||||
|
string wrapped;
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
size_t linelen = 0;
|
||||||
|
while (words[index] != '\0')
|
||||||
|
{
|
||||||
|
if (words[index] == '\n')
|
||||||
|
{
|
||||||
|
linelen = 0;
|
||||||
|
}
|
||||||
|
else if (isspace(words[index]))
|
||||||
|
{
|
||||||
|
size_t tempindex = index + 1;
|
||||||
|
size_t templinelen = linelen;
|
||||||
|
while (!isspace(words[tempindex]) and words[tempindex] != '\0')
|
||||||
|
{
|
||||||
|
++templinelen;
|
||||||
|
|
||||||
|
++tempindex;
|
||||||
|
}
|
||||||
|
|
||||||
|
char temp[templinelen + 1];
|
||||||
|
strncpy(temp, words + (index - linelen), templinelen);
|
||||||
|
temp[templinelen] = '\0';
|
||||||
|
|
||||||
|
size_t width = strcol(temp);
|
||||||
|
|
||||||
|
if (width >= line_length)
|
||||||
|
{
|
||||||
|
words[index] = '\n';
|
||||||
|
linelen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (words[index] == '\t')
|
||||||
|
linelen += 8 - (linelen % 8);
|
||||||
|
else if (words[index] != '\n')
|
||||||
|
++linelen;
|
||||||
|
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
wrapped = words;
|
||||||
|
return wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output char array as table
|
||||||
|
int table(const size_t rows, const size_t columns, char ***array, const tableoptions &aoptions)
|
||||||
|
{
|
||||||
|
if (array == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
const bool headerrow = aoptions.headerrow;
|
||||||
|
const bool headercolumn = aoptions.headercolumn;
|
||||||
|
const bool tableborder = aoptions.tableborder;
|
||||||
|
const bool cellborder = aoptions.cellborder;
|
||||||
|
const unsigned int padding = aoptions.padding;
|
||||||
|
const char *const title = aoptions.title;
|
||||||
|
const unsigned int style = aoptions.style;
|
||||||
|
|
||||||
|
if (style >= (sizeof styles / sizeof styles[0]))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int columnwidth[columns];
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
columnwidth[j] = 0;
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
|
||||||
|
setlocale(LC_CTYPE, "");
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
int cellwidth = strcol(array[i][j]);
|
||||||
|
if (cellwidth > columnwidth[j])
|
||||||
|
columnwidth[j] = cellwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
width += columnwidth[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct winsize w;
|
||||||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
|
|
||||||
|
if (tableborder and (cellborder or headerrow or headercolumn))
|
||||||
|
width += (((2 * padding) + 1) * columns) + 1;
|
||||||
|
else
|
||||||
|
width += ((2 * padding) * columns) + 2;
|
||||||
|
|
||||||
|
if (width > w.ws_col)
|
||||||
|
{
|
||||||
|
cerr << "The width of the table (" << width << ") is greater then the width of the terminal (" << w.ws_col << ").\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (title != NULL and title[0] != '\0')
|
||||||
|
cout << wrap(title, w.ws_col) << "\n";
|
||||||
|
|
||||||
|
if (tableborder)
|
||||||
|
{
|
||||||
|
cout << styles[style][2];
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < (2 * padding) + columnwidth[j]; ++k)
|
||||||
|
cout << styles[style][0];
|
||||||
|
|
||||||
|
if (j == (columns - 1))
|
||||||
|
cout << styles[style][4] << "\n";
|
||||||
|
else if (cellborder or headerrow or (j == 0 and headercolumn))
|
||||||
|
cout << styles[style][3];
|
||||||
|
else
|
||||||
|
cout << styles[style][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
if (tableborder)
|
||||||
|
{
|
||||||
|
if (j == 0 or cellborder or (i == 0 and headerrow) or (j == 1 and headercolumn))
|
||||||
|
cout << styles[style][1];
|
||||||
|
else
|
||||||
|
cout << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i == 0 and headerrow) or (j == 0 and headercolumn))
|
||||||
|
{
|
||||||
|
int difference = columnwidth[j] - strcol(array[i][j]);
|
||||||
|
int apadding = (difference / 2);
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < padding + apadding; ++k)
|
||||||
|
cout << " ";
|
||||||
|
|
||||||
|
cout << "\e[1m" << array[i][j] << "\e[22m";
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < padding + (difference - apadding); ++k)
|
||||||
|
cout << " ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < padding; ++k)
|
||||||
|
cout << " ";
|
||||||
|
|
||||||
|
cout << aoptions.alignment << setw(columnwidth[j]) << array[i][j];
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < padding; ++k)
|
||||||
|
cout << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tableborder)
|
||||||
|
cout << styles[style][1];
|
||||||
|
|
||||||
|
cout << "\n";
|
||||||
|
|
||||||
|
if (tableborder)
|
||||||
|
{
|
||||||
|
if (i == (rows - 1))
|
||||||
|
cout << styles[style][8];
|
||||||
|
else if (cellborder or (i == 0 and headerrow) or headercolumn)
|
||||||
|
cout << styles[style][5];
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
if (cellborder or i == (rows - 1) or (i == 0 and headerrow) or (j == 0 and headercolumn))
|
||||||
|
for (unsigned int k = 0; k < (2 * padding) + columnwidth[j]; ++k)
|
||||||
|
cout << styles[style][0];
|
||||||
|
else if (headercolumn)
|
||||||
|
for (unsigned int k = 0; k < (2 * padding) + columnwidth[j]; ++k)
|
||||||
|
cout << " ";
|
||||||
|
|
||||||
|
if (j == (columns - 1))
|
||||||
|
{
|
||||||
|
if (i == (rows - 1))
|
||||||
|
cout << styles[style][10];
|
||||||
|
else if (cellborder or (i == 0 and headerrow))
|
||||||
|
cout << styles[style][7];
|
||||||
|
else if (headercolumn)
|
||||||
|
cout << styles[style][1];
|
||||||
|
|
||||||
|
if (cellborder or (i == 0 and headerrow) or headercolumn)
|
||||||
|
cout << "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (i == (rows - 1))
|
||||||
|
{
|
||||||
|
if (cellborder or (j == 0 and headercolumn))
|
||||||
|
cout << styles[style][9];
|
||||||
|
else
|
||||||
|
cout << styles[style][0];
|
||||||
|
}
|
||||||
|
else if (cellborder or ((i == 0 and headerrow) and (j == 0 and headercolumn)))
|
||||||
|
cout << styles[style][6];
|
||||||
|
else if (i == 0 and headerrow)
|
||||||
|
cout << styles[style][9];
|
||||||
|
else if (headercolumn)
|
||||||
|
{
|
||||||
|
if (j == 0)
|
||||||
|
cout << styles[style][7];
|
||||||
|
else
|
||||||
|
cout << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert array to char array and output as table
|
||||||
|
template <typename T>
|
||||||
|
int table(size_t rows, size_t columns, T **array, const char *const headerrow[], const char *const headercolumn[], const tableoptions &aoptions)
|
||||||
|
{
|
||||||
|
if (array == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unsigned int i = 0;
|
||||||
|
unsigned int j = 0;
|
||||||
|
|
||||||
|
if (headerrow != NULL)
|
||||||
|
++rows;
|
||||||
|
|
||||||
|
if (headercolumn != NULL)
|
||||||
|
++columns;
|
||||||
|
|
||||||
|
char ***aarray;
|
||||||
|
aarray = new char **[rows];
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
aarray[i] = new char *[columns];
|
||||||
|
|
||||||
|
if (headerrow != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
aarray[i][j] = new char[strlen(headerrow[j]) + 1];
|
||||||
|
strcpy(aarray[i][j], headerrow[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int ii = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
if (headercolumn != NULL)
|
||||||
|
{
|
||||||
|
unsigned int ii = i;
|
||||||
|
|
||||||
|
if (headerrow != NULL)
|
||||||
|
--ii;
|
||||||
|
|
||||||
|
aarray[i][j] = new char[strlen(headercolumn[ii]) + 1];
|
||||||
|
strcpy(aarray[i][j], headercolumn[ii]);
|
||||||
|
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int jj = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
ostringstream strm;
|
||||||
|
|
||||||
|
if (aoptions.boolalpha)
|
||||||
|
strm << boolalpha;
|
||||||
|
|
||||||
|
strm << array[ii][jj];
|
||||||
|
string str = strm.str();
|
||||||
|
aarray[i][j] = new char[str.length() + 1];
|
||||||
|
strcpy(aarray[i][j], str.c_str());
|
||||||
|
|
||||||
|
++jj;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
++ii;
|
||||||
|
}
|
||||||
|
|
||||||
|
int code = table(rows, columns, aarray, aoptions);
|
||||||
|
|
||||||
|
if (aarray != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
delete[] aarray[i][j];
|
||||||
|
|
||||||
|
delete[] aarray[i];
|
||||||
|
}
|
||||||
|
delete[] aarray;
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert one or more functions to array and output as table
|
||||||
|
template <typename T>
|
||||||
|
int table(const long double xmin, const long double xmax, const long double xscl, const size_t numfunctions, T (*functions[])(T), const tableoptions &aoptions)
|
||||||
|
{
|
||||||
|
if (numfunctions == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (xmin >= xmax)
|
||||||
|
{
|
||||||
|
cerr << "xmin must be less than xmax.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xscl <= 0)
|
||||||
|
{
|
||||||
|
cerr << "xscl must be greater than zero.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t rows = ((xmax - xmin) * xscl) + 1;
|
||||||
|
const size_t columns = numfunctions + 1;
|
||||||
|
|
||||||
|
const char *const aheaderrow[] = {"x", "y"};
|
||||||
|
// const char* const aheaderrow[] = {"", "x", "y"};
|
||||||
|
|
||||||
|
char **headerrow = NULL;
|
||||||
|
headerrow = new char *[columns];
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
const size_t length = (sizeof aheaderrow / sizeof aheaderrow[0]);
|
||||||
|
|
||||||
|
if (j < (length - 1) or numfunctions == 1)
|
||||||
|
{
|
||||||
|
headerrow[j] = new char[strlen(aheaderrow[j]) + 1];
|
||||||
|
strcpy(headerrow[j], aheaderrow[j]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ostringstream strm;
|
||||||
|
strm << aheaderrow[length - 1] << j - length + 2;
|
||||||
|
string str = strm.str();
|
||||||
|
headerrow[j] = new char[str.length() + 1];
|
||||||
|
strcpy(headerrow[j], str.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char **headercolumn = NULL;
|
||||||
|
// headercolumn = new char *[rows + 1];
|
||||||
|
|
||||||
|
// for (unsigned int i = 0; i < rows + 1; ++i)
|
||||||
|
// {
|
||||||
|
// ostringstream strm;
|
||||||
|
// strm << i + 1;
|
||||||
|
// string str = strm.str();
|
||||||
|
// headercolumn[i] = new char[str.length() + 1];
|
||||||
|
// strcpy(headercolumn[i], str.c_str());
|
||||||
|
// }
|
||||||
|
|
||||||
|
T **array;
|
||||||
|
array = new T *[rows];
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
array[i] = new T[columns];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
array[i][0] = (i / xscl) + xmin;
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < numfunctions; ++j)
|
||||||
|
array[i][j + 1] = (functions[j])(array[i][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int code = table(rows, columns, array, headerrow, headercolumn, aoptions);
|
||||||
|
|
||||||
|
if (array != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < rows; ++i)
|
||||||
|
delete[] array[i];
|
||||||
|
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerrow != NULL)
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < columns; ++j)
|
||||||
|
delete[] headerrow[j];
|
||||||
|
|
||||||
|
delete[] headerrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (headercolumn != NULL)
|
||||||
|
// {
|
||||||
|
// for (unsigned int i = 0; i < rows + 1; ++i)
|
||||||
|
// delete[] headercolumn[i];
|
||||||
|
|
||||||
|
// delete[] headercolumn;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert single function to array and output as table
|
||||||
|
template <typename T>
|
||||||
|
int table(const long double xmin, const long double xmax, const long double xscl, T afunction(T), const tableoptions &aoptions)
|
||||||
|
{
|
||||||
|
T(*functions[])
|
||||||
|
(T) = {afunction};
|
||||||
|
|
||||||
|
return table(xmin, xmax, xscl, 1, functions, aoptions);
|
||||||
|
}
|