728 lines
24 KiB
C++
728 lines
24 KiB
C++
/*
|
||
* (c) Copyright Ascensio System SIA 2010-2023
|
||
*
|
||
* This program is a free software product. You can redistribute it and/or
|
||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||
* version 3 as published by the Free Software Foundation. In accordance with
|
||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||
* of any third-party rights.
|
||
*
|
||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||
*
|
||
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
||
* street, Riga, Latvia, EU, LV-1050.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of the Program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU AGPL version 3.
|
||
*
|
||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||
* grant you any rights under trademark law for use of our trademarks.
|
||
*
|
||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||
* well as technical writing content are licensed under the terms of the
|
||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||
*
|
||
*/
|
||
#include <iostream>
|
||
#include <math.h>
|
||
#include <vector>
|
||
|
||
#include "../agg-2.4/include/agg_color_rgba.h"
|
||
#include "../graphics/aggplustypes.h"
|
||
#include "../graphics/Matrix.h"
|
||
|
||
#ifndef M_PI
|
||
#define M_PI 3.14159265358979323846
|
||
#endif
|
||
|
||
#ifndef SHADING_INFO
|
||
#define SHADING_INFO
|
||
|
||
namespace NSStructures
|
||
{
|
||
/**
|
||
*
|
||
* */
|
||
template <class ColorT = agg::rgba8>
|
||
class ColorFunction
|
||
/**
|
||
* Реализацию произвольной функции в рантайме я решил сделать как массив, тк так проще всего
|
||
* я еще не совсем понял как точно передается в пдфе функция, но такая реализация, позволяет пользователю
|
||
* выбрать любой способ.
|
||
*
|
||
* Пока все копируется, т.к. в большинсве случаев вектор 2кБ по размеру и проблем нету
|
||
* только если использовать двумерную функцию размер возрастает до МБ, но не хочется возится с укузателями
|
||
* ради этого, т.к. судя по всему случай исключительный(только 1 шейдинг требует такую функцию).
|
||
* Если надо будет, наверно можно будет переписать на юникптр.
|
||
*
|
||
* Есть возможность выставить обычную линейную интерполяцию, просто для тестирования
|
||
* + так реализуется градиент стандартный.
|
||
*
|
||
* Пока у меня конструкторы по умолчанию, чтото заполняют, для тестирования опятьже
|
||
* потом стоит все убрать, чтобы в кисти не таскать это все, когда оно не нужно,
|
||
* если не выделять память то там в сумме будет <100B гдето, не думаю, что это будет так много,
|
||
* чтобы писать отдельный интерфейс для кисти
|
||
*
|
||
* Плюс я вообще не знаю как обрабатывать, внештатные ситуации, в целом, можно вообще просто
|
||
* эксепшены кидать если что или ничего не делать.
|
||
*/
|
||
{
|
||
public:
|
||
ColorFunction() : RESOLUTION(0), x_domain_min(0.0f), x_domain_max(0.0f)
|
||
{
|
||
|
||
}
|
||
|
||
ColorFunction(size_t res, float xmin, float xmax) : RESOLUTION(res), x_domain_min(xmin), x_domain_max(xmax)
|
||
|
||
{
|
||
values = std::vector<std::vector<ColorT>>(1, std::vector<ColorT>(RESOLUTION));
|
||
for (size_t i = 0; i < RESOLUTION; i++)
|
||
{
|
||
unsigned int value = (unsigned int)(255 - (255 * ((float)i / RESOLUTION)));
|
||
values[0][i] = ColorT(value, value, value);
|
||
}
|
||
}
|
||
|
||
ColorFunction(size_t res, float xmin, float xmax, float ymin, float ymax) : RESOLUTION(res), x_domain_min(xmin), x_domain_max(xmax), y_domain_min(ymin), y_domain_max(ymax)
|
||
{
|
||
values = std::vector<std::vector<ColorT>>(RESOLUTION, std::vector<ColorT>(RESOLUTION));
|
||
for (size_t i = 0; i < RESOLUTION; i++)
|
||
{
|
||
for (size_t j = 0; j < RESOLUTION; j++)
|
||
{
|
||
unsigned int value = (unsigned int)(255 * sin(i * j * M_PI / RESOLUTION));
|
||
values[j][i] = ColorT(255, 0, 0, 255);
|
||
}
|
||
}
|
||
}
|
||
|
||
void set_x_min(float x_min)
|
||
{
|
||
x_domain_min = x_min;
|
||
}
|
||
void set_x_max(float x_max)
|
||
{
|
||
x_domain_max = x_max;
|
||
}
|
||
void set_y_min(float y_min)
|
||
{
|
||
y_domain_min = y_min;
|
||
}
|
||
void set_y_max(float y_max)
|
||
{
|
||
y_domain_max = y_max;
|
||
}
|
||
|
||
float get_x_min()
|
||
{
|
||
return x_domain_min;
|
||
}
|
||
float get_x_max()
|
||
{
|
||
return x_domain_max;
|
||
}
|
||
float get_y_min()
|
||
{
|
||
return y_domain_min;
|
||
}
|
||
float get_y_max()
|
||
{
|
||
return y_domain_max;
|
||
}
|
||
ColorT get_color(float x)
|
||
{
|
||
int index = get_x_index(x);
|
||
return values[0][index];
|
||
}
|
||
|
||
//used only in shading type 1
|
||
ColorT get_color(float x, float y)
|
||
{
|
||
int xi = get_x_index(x);
|
||
int yi = get_y_index(y);
|
||
//std::cout << x << ' ' << y << std::endl;
|
||
return values[yi][xi];
|
||
}
|
||
|
||
void set_color(float x, int r, int g, int b, int a)
|
||
{
|
||
int index = get_x_index(x); // pls dont set color out of bounds, it wont crush, but will work not as you max expected
|
||
values[0][index].r = r;
|
||
values[0][index].g = g;
|
||
values[0][index].b = b;
|
||
values[0][index].a = a;
|
||
}
|
||
void set_color(float x, float y, int r, int g, int b, int a)
|
||
{
|
||
int xindex = get_x_index(x);
|
||
int yindex = get_y_index(y);
|
||
values[yindex][xindex].r = r;
|
||
values[yindex][xindex].g = g;
|
||
values[yindex][xindex].b = b;
|
||
values[yindex][xindex].a = a;
|
||
}
|
||
void set_color(size_t xindex, int r, int g, int b, int a)
|
||
{
|
||
values[0][xindex].r = r;
|
||
values[0][xindex].g = g;
|
||
values[0][xindex].b = b;
|
||
values[0][xindex].a = a;
|
||
}
|
||
void set_color(size_t xindex, size_t yindex, int r, int g, int b, int a)
|
||
{
|
||
values[yindex][xindex].r = r;
|
||
values[yindex][xindex].g = g;
|
||
values[yindex][xindex].b = b;
|
||
values[yindex][xindex].a = a;
|
||
}
|
||
// position must be sorted by incr ub otherwise
|
||
// only for 1 in function
|
||
int set_linear_interpolation(const std::vector<uint32_t> &colors, const std::vector<float> &positions)
|
||
{
|
||
if (colors.size() != positions.size())
|
||
{
|
||
return -1; // error
|
||
}
|
||
std::vector<int> indexes;
|
||
for (float x : positions)
|
||
{
|
||
indexes.push_back(get_x_index(x));
|
||
}
|
||
for (int i = 0; i < colors.size(); i++)
|
||
{
|
||
values[0][indexes[i]].r = hex2r(colors[i]);
|
||
values[0][indexes[i]].g = hex2g(colors[i]);
|
||
values[0][indexes[i]].b = hex2b(colors[i]);
|
||
values[0][indexes[i]].a = hex2a(colors[i]);
|
||
|
||
}
|
||
for (int i = 0; i < positions.size() - 1; i++)
|
||
{
|
||
interpolate_indexes(indexes[i], indexes[i + 1]);
|
||
}
|
||
return 0;
|
||
}
|
||
size_t get_resolution() const
|
||
{
|
||
return RESOLUTION;
|
||
}
|
||
private:
|
||
size_t RESOLUTION;
|
||
std::vector<std::vector<ColorT>> values;
|
||
float x_domain_min, x_domain_max;
|
||
float y_domain_min, y_domain_max;
|
||
int get_x_index(float x)
|
||
{
|
||
int x_index = (int)(RESOLUTION - 1) * (x - x_domain_min) / (x_domain_max - x_domain_min);
|
||
if (x_index < 0)
|
||
return 0;
|
||
if (x_index > RESOLUTION - 1)
|
||
return RESOLUTION - 1;
|
||
return x_index;
|
||
}
|
||
int get_y_index(float y)
|
||
{
|
||
int y_index = (int)(RESOLUTION - 1) * (y - y_domain_min) / (y_domain_max - y_domain_min);
|
||
if (values.size() < RESOLUTION)
|
||
{
|
||
return 0;
|
||
}
|
||
if (y_index < 0)
|
||
return 0;
|
||
if (y_index > RESOLUTION - 1)
|
||
return RESOLUTION - 1;
|
||
return y_index;
|
||
}
|
||
/**
|
||
* Линейная интерполяция для построения цветовой функции.
|
||
*/
|
||
int interpolate_indexes(size_t first, size_t second, size_t line = 0)
|
||
{
|
||
size_t len = second - first;
|
||
ColorT f = values[line][first];
|
||
ColorT s = values[line][second];
|
||
for(size_t i = first + 1; i < second; i++) {
|
||
values[line][i].r = f.r * (1 - (float)(i - first) / len ) + s.r * ((float)(i - first) / len );
|
||
values[line][i].g = f.g * (1 - (float)(i - first) / len ) + s.g * ((float)(i - first) / len ); ;
|
||
values[line][i].b = f.b * (1 - (float)(i - first) / len ) + s.b * ((float)(i - first) / len ); ;
|
||
values[line][i].a = f.a * (1 - (float)(i - first) / len ) + s.a * ((float)(i - first) / len ); ;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
unsigned int hex2a(uint32_t c)
|
||
{
|
||
unsigned int a = (c >> 24) & 0xFF;
|
||
return a;
|
||
}
|
||
|
||
unsigned int hex2r(uint32_t c)
|
||
{
|
||
return (c >> 16) & 0xFF;
|
||
}
|
||
unsigned int hex2g(uint32_t c)
|
||
{
|
||
return (c >> 8) & 0xFF;
|
||
}
|
||
unsigned int hex2b(uint32_t c)
|
||
{
|
||
return c & 0xFF;
|
||
}
|
||
};
|
||
|
||
struct Point
|
||
{
|
||
Point():x(0),y(0){}
|
||
Point(const float& _x, const float& _y):x(_x),y(_y){}
|
||
Point(const int& _x, const int& _y):x((float)_x),y((float)_y){}
|
||
Point(const double& _x, const double& _y):x((float)_x),y((float)_y){}
|
||
float x, y;
|
||
|
||
Point& operator+=(const Point &a)
|
||
{
|
||
x += a.x;
|
||
y += a.y;
|
||
return *this;
|
||
}
|
||
|
||
|
||
/**
|
||
* Костыль от ошибок линковки. Чтобы время не терять пока что.
|
||
*/
|
||
friend Point operator*(const Point &a, float t)
|
||
{
|
||
return Point(a.x * t, a.y * t);
|
||
}
|
||
friend Point operator*(float t, const Point &a)
|
||
{
|
||
return Point(a.x * t, a.y * t);
|
||
}
|
||
friend Point operator+(const Point &a, const Point &b)
|
||
{
|
||
return Point(a.x + b.x, a.y + b.y);
|
||
}
|
||
friend Point operator-(const Point &a, const Point &b)
|
||
{
|
||
return Point(a.x - b.x, a.y - b.y);
|
||
}
|
||
};
|
||
|
||
|
||
|
||
/**
|
||
* Тут хранится информация спецефичная для рендера ПДФ.
|
||
*
|
||
* Взял новую реализацию преобразований, т.к. готовая была на даблах,
|
||
* а в такой точности смысла нету особо.
|
||
*
|
||
* Для шейдеров требуется поддерживать два способа вычисления (с параметром и без),
|
||
* поэтому требуется много дополнительной инфы.
|
||
*
|
||
* Так же шейдер будет получать, в качетве параметров, границы, тут я пока не решил, вообще
|
||
* можно оставить соблюдение границ, на откуп пользователю, т.к. все равно заполенение в конечном итоге будет
|
||
* выполняться с помощью рисования замкнутого пути и команды Fill
|
||
* */
|
||
struct ShadingInfo
|
||
{
|
||
public:
|
||
ShadingInfo() : shading_type(Parametric), f_type(UseNew), inv_map(6){}
|
||
enum ShadingType
|
||
{
|
||
FunctionOnly,
|
||
Parametric,
|
||
TriangleInterpolation,
|
||
CurveInterpolation,
|
||
TensorCurveInterpolation
|
||
} shading_type;
|
||
|
||
// if UseOld old function is called, look for IGraphicsRender.put_BrushGradientColors;
|
||
enum ColorFunctionType
|
||
{
|
||
UseOld, UseNew
|
||
} f_type;
|
||
ColorFunction<agg::rgba8> function;
|
||
|
||
// Обратное преобразование из картинки в цветовую функцию
|
||
std::vector<float> mapping;
|
||
std::vector<float> inv_map;
|
||
|
||
// Линейный градиент задается в pdf 2 точками
|
||
bool set_two_points;
|
||
Point point1, point2;
|
||
|
||
|
||
// triangle shading
|
||
std::vector<Point> triangle;
|
||
std::vector<agg::rgba8> triangle_colors;
|
||
std::vector<float> triangle_parameters;
|
||
|
||
/**
|
||
* Матрица 4 на 4 заполняется как в документации к пдф 7 тип
|
||
* Если выбран тип 6 то значения (1,2) (2,1) (1,1) (2,2)
|
||
* В массиве игнормруется и заполняются автоматически, следите за переданным типом градинта
|
||
* (Нумерация от нуля)
|
||
*
|
||
* Наверное напишу адаптор который переводит порядок точек из 6 типа в общий.
|
||
*/
|
||
agg::rgba8 fill_color;
|
||
std::vector<std::vector<Point>> patch;
|
||
std::vector<std::vector<agg::rgba8>> patch_colors; // 2 на 2 цвета по углам
|
||
std::vector<std::vector<float>> patch_parameters; // 2 на 2 параметра
|
||
};
|
||
|
||
// Containing additional info about gradient
|
||
struct GradientInfo
|
||
{
|
||
GradientInfo() : littleRadius(0.0f), largeRadius(1.0f),
|
||
centerX(0.0f), centerY(0.0f),
|
||
angle(0.0f),
|
||
discrete_step(0.0f),
|
||
reflected(false),
|
||
periods(0.5f), periodic(false),
|
||
xsize(1.0f), ysize(1.0f),
|
||
linstretch(1.0f), linoffset(0.0f),
|
||
continue_shading_f(false),
|
||
continue_shading_b(false),
|
||
luminocity(false)
|
||
{
|
||
}
|
||
void setAngleDegrees(float deg)
|
||
{
|
||
angle = deg / 180.f * (float)M_PI;
|
||
}
|
||
float getAngleDegrees() const
|
||
{
|
||
return angle / (float)M_PI * 180.f;
|
||
}
|
||
void setStepByNum(int n) // recommended to use
|
||
{
|
||
discrete_step = 1.0f / n;
|
||
}
|
||
bool checkLuminosity() const
|
||
{
|
||
if (shading.patch_colors.empty())
|
||
return false;
|
||
|
||
for (const auto& ar : shading.patch_colors)
|
||
for (const auto& c : ar)
|
||
if (c.r != c.g || c.g != c.b)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
bool colorEqual(const agg::rgba8& c1, const agg::rgba8& c2) const
|
||
{
|
||
return c1.r == c2.r &&
|
||
c1.g == c2.g &&
|
||
c1.b == c2.b &&
|
||
c1.a == c2.a;
|
||
}
|
||
bool isOneColor() const
|
||
{
|
||
switch (shading.shading_type)
|
||
{
|
||
case ShadingInfo::FunctionOnly:
|
||
case ShadingInfo::Parametric:
|
||
return false;
|
||
case ShadingInfo::TriangleInterpolation:
|
||
return colorEqual(shading.triangle_colors[0], shading.triangle_colors[1]) &&
|
||
colorEqual(shading.triangle_colors[1], shading.triangle_colors[2]);
|
||
case ShadingInfo::CurveInterpolation:
|
||
case ShadingInfo::TensorCurveInterpolation:
|
||
return colorEqual(shading.patch_colors[0][0], shading.patch_colors[0][1]) &&
|
||
colorEqual(shading.patch_colors[0][1], shading.patch_colors[1][0]) &&
|
||
colorEqual(shading.patch_colors[1][0], shading.patch_colors[1][1]);
|
||
default:
|
||
return false;
|
||
}
|
||
}
|
||
agg::rgba8 getFillColor() const
|
||
{
|
||
if (!shading.triangle_colors.empty())
|
||
return shading.triangle_colors[0];
|
||
if (!shading.patch_colors.empty())
|
||
return shading.patch_colors[0][0];
|
||
return agg::rgba8(0, 0, 0);
|
||
}
|
||
void setFillColor(const agg::rgba8& color)
|
||
{
|
||
shading.fill_color = color;
|
||
luminocity = true;
|
||
}
|
||
void transform(const Aggplus::CMatrix& matrix)
|
||
{
|
||
// shading transform
|
||
auto& point1 = shading.point1;
|
||
auto& point2 = shading.point2;
|
||
|
||
double point1_x = static_cast<double>(point1.x);
|
||
double point1_y = static_cast<double>(point1.y);
|
||
double point2_x = static_cast<double>(point2.x);
|
||
double point2_y = static_cast<double>(point2.y);
|
||
|
||
matrix.TransformPoint(point1_x, point1_y);
|
||
matrix.TransformPoint(point2_x, point2_y);
|
||
|
||
point1.x = static_cast<float>(point1_x);
|
||
point1.y = static_cast<float>(point1_y);
|
||
point2.x = static_cast<float>(point2_x);
|
||
point2.y = static_cast<float>(point2_y);
|
||
|
||
// triangle transform
|
||
for (auto& p : shading.triangle)
|
||
{
|
||
double triangle_x = static_cast<double>(p.x);
|
||
double triangle_y = static_cast<double>(p.y);
|
||
|
||
matrix.TransformPoint(triangle_x, triangle_y);
|
||
|
||
p.x = static_cast<float>(triangle_x);
|
||
p.y = static_cast<float>(triangle_y);
|
||
}
|
||
|
||
// domains transform
|
||
double x_domain_min = static_cast<double>(shading.function.get_x_min());
|
||
double y_domain_min = static_cast<double>(shading.function.get_y_min());
|
||
double x_domain_max = static_cast<double>(shading.function.get_x_max());
|
||
double y_domain_max = static_cast<double>(shading.function.get_y_max());
|
||
|
||
matrix.TransformPoint(x_domain_min, y_domain_min);
|
||
matrix.TransformPoint(x_domain_max, y_domain_max);
|
||
|
||
shading.function.set_x_min(static_cast<float>(x_domain_min));
|
||
shading.function.set_y_min(static_cast<float>(y_domain_min));
|
||
shading.function.set_x_max(static_cast<float>(x_domain_max));
|
||
shading.function.set_y_max(static_cast<float>(y_domain_max));
|
||
|
||
// center transform
|
||
double center_x = static_cast<double>(centerX);
|
||
double center_y = static_cast<double>(centerY);
|
||
|
||
matrix.TransformPoint(center_x, center_y);
|
||
|
||
double p0_x = static_cast<double>(p0.x);
|
||
double p0_y = static_cast<double>(p0.y);
|
||
double p1_x = static_cast<double>(p1.x);
|
||
double p1_y = static_cast<double>(p1.y);
|
||
|
||
matrix.TransformPoint(p0_x, p0_y);
|
||
matrix.TransformPoint(p1_x, p1_y);
|
||
|
||
p0.x = static_cast<float>(p0_x);
|
||
p0.y = static_cast<float>(p0_y);
|
||
p1.x = static_cast<float>(p1_x);
|
||
p1.y = static_cast<float>(p1_y);
|
||
|
||
for (size_t i = 0; i < shading.patch.size(); ++i)
|
||
{
|
||
for (size_t j = 0; j < shading.patch[i].size(); ++j)
|
||
{
|
||
double patch_x = static_cast<double>(shading.patch[i][j].x);
|
||
double patch_y = static_cast<double>(shading.patch[i][j].y);
|
||
|
||
matrix.TransformPoint(patch_x, patch_y);
|
||
|
||
shading.patch[i][j].x = static_cast<float>(patch_x);
|
||
shading.patch[i][j].y = static_cast<float>(patch_y);
|
||
}
|
||
}
|
||
|
||
// sizes scale
|
||
double sqrt_det = sqrt(fabs(matrix.Determinant()));
|
||
r0 *= sqrt_det;
|
||
r1 *= sqrt_det;
|
||
}
|
||
|
||
Point p0, p1;
|
||
float r0, r1;
|
||
|
||
float littleRadius, largeRadius;
|
||
float centerX, centerY; // used in radial, diamond and conical gradient - offset relative to figure center
|
||
float angle; // used in linear and conical gradient (rad)
|
||
float discrete_step; // used to make discrete gradient. <= 0 to make continuous
|
||
float xsize, ysize; // stretch image; can be negative to reflect relative to other axis; cannot be zero
|
||
bool reflected; // 1234567 -> 1357531 works kind of like this
|
||
bool periodic;
|
||
float periods; // number of periods (best with to colours, works as saw function in color space)
|
||
float linstretch; // stretch linear gradient, can be negative (eq angle = 180) can not be zero
|
||
float linoffset; // offset relative to image size
|
||
float continue_shading_b, continue_shading_f;
|
||
bool luminocity;
|
||
ShadingInfo shading;
|
||
};
|
||
|
||
|
||
/**
|
||
* Создает объект класса GradientInfo по заданным параметрам.
|
||
*
|
||
* Цветовую функцию надо заполнять вручную
|
||
*/
|
||
class GInfoConstructor {
|
||
public:
|
||
static GradientInfo get_functional(float xmin, float xmax, float ymin, float ymax,
|
||
std::vector<float> mapping)
|
||
{
|
||
GradientInfo ginfo;
|
||
ginfo.shading.function = ColorFunction<agg::rgba8>(256, xmin, xmax, ymin, ymax);
|
||
ginfo.shading.f_type = ShadingInfo::UseNew;
|
||
ginfo.shading.shading_type = ShadingInfo::FunctionOnly;
|
||
|
||
ginfo.shading.mapping = mapping;
|
||
|
||
return ginfo;
|
||
}
|
||
static GradientInfo get_linear(const Point &p1, const Point &p2, float t0 = 0.0f, float t1 = 1.0f,
|
||
bool continue_shading_b = false, bool continue_shading_f = false)
|
||
{
|
||
GradientInfo ginfo;
|
||
ginfo.shading.f_type = ShadingInfo::UseNew;
|
||
ginfo.shading.shading_type = ShadingInfo::Parametric;
|
||
ginfo.continue_shading_f = continue_shading_f;
|
||
ginfo.continue_shading_b = continue_shading_b;
|
||
|
||
ginfo.shading.function = ColorFunction<agg::rgba8>(256, t0, t1);
|
||
|
||
ginfo.shading.set_two_points = true;
|
||
ginfo.shading.point1 = p1;
|
||
ginfo.shading.point2 = p2;
|
||
|
||
|
||
return ginfo;
|
||
}
|
||
static GradientInfo get_radial(const Point &c0, const Point &c1, float r0, float r1,
|
||
float t0 = 0.0f, float t1 = 1.0f,
|
||
bool continue_shading_b = false, bool continue_shading_f = false)
|
||
{
|
||
GradientInfo ginfo;
|
||
ginfo.shading.f_type = ShadingInfo::UseNew;
|
||
ginfo.shading.shading_type = ShadingInfo::Parametric;
|
||
ginfo.continue_shading_f = continue_shading_f;
|
||
ginfo.continue_shading_b = continue_shading_b;
|
||
ginfo.shading.function = ColorFunction<agg::rgba8>(256, t0, t1);
|
||
ginfo.p0 = c0;
|
||
ginfo.p1 = c1;
|
||
ginfo.r0 = r0;
|
||
ginfo.r1 = r1;
|
||
return ginfo;
|
||
|
||
|
||
}
|
||
static GradientInfo get_triangle(const std::vector<Point> &points,
|
||
const std::vector<agg::rgba8> &colors,
|
||
const std::vector<float> ¶ms,
|
||
bool parametric,
|
||
float t0 = 0.0f, float t1 = 1.0f)
|
||
{
|
||
GradientInfo ginfo;
|
||
ginfo.shading.triangle = points;
|
||
ginfo.shading.shading_type = ShadingInfo::Parametric;
|
||
ginfo.shading.function = ColorFunction<agg::rgba8>(256, t0, t1);
|
||
ginfo.continue_shading_f = false;
|
||
ginfo.continue_shading_b = false;
|
||
if (parametric)
|
||
{
|
||
ginfo.shading.triangle_parameters = params;
|
||
ginfo.shading.shading_type = ShadingInfo::Parametric;
|
||
}
|
||
else
|
||
{
|
||
ginfo.shading.triangle_colors = colors;
|
||
ginfo.shading.shading_type = ShadingInfo::TriangleInterpolation;
|
||
}
|
||
return ginfo;
|
||
}
|
||
|
||
/**
|
||
* Набор из 12 точек для построения границ в порядке указанном в стандарте,
|
||
* Порядок цветов или параметров как в стандарте.
|
||
*/
|
||
static GradientInfo get_curve(const std::vector<Point> &curve_points,
|
||
const std::vector<float> &curve_parametrs,
|
||
const std::vector<agg::rgba8> &curve_colors,
|
||
bool parametric,
|
||
float t0 = 0.0f, float t1 = 1.0f)
|
||
{
|
||
GradientInfo ginfo;
|
||
ginfo.shading.patch.resize(4, std::vector<Point>(4));
|
||
ginfo.shading.patch[0][0] = curve_points[0];
|
||
ginfo.shading.patch[0][1] = curve_points[1];
|
||
ginfo.shading.patch[0][2] = curve_points[2];
|
||
|
||
ginfo.shading.patch[0][3] = curve_points[3];
|
||
ginfo.shading.patch[1][3] = curve_points[4];
|
||
ginfo.shading.patch[2][3] = curve_points[5];
|
||
|
||
ginfo.shading.patch[3][3] = curve_points[6];
|
||
ginfo.shading.patch[3][2] = curve_points[7];
|
||
ginfo.shading.patch[3][1] = curve_points[8];
|
||
|
||
ginfo.shading.patch[3][0] = curve_points[9];
|
||
ginfo.shading.patch[2][0] = curve_points[10];
|
||
ginfo.shading.patch[1][0] = curve_points[11];
|
||
|
||
ginfo.shading.f_type = ShadingInfo::UseNew;
|
||
ginfo.shading.function = ColorFunction<agg::rgba8>(256, t0, t1);
|
||
ginfo.continue_shading_f = false;
|
||
ginfo.continue_shading_b = false;
|
||
|
||
if (parametric)
|
||
{
|
||
ginfo.shading.patch_parameters.resize(2, std::vector<float>(2));
|
||
ginfo.shading.patch_parameters[0][0] = curve_parametrs[0];
|
||
ginfo.shading.patch_parameters[0][1] = curve_parametrs[1];
|
||
ginfo.shading.patch_parameters[1][0] = curve_parametrs[3];
|
||
ginfo.shading.patch_parameters[1][1] = curve_parametrs[2];
|
||
ginfo.shading.shading_type = ShadingInfo::Parametric;
|
||
}
|
||
else
|
||
{
|
||
ginfo.shading.patch_colors.resize(2, std::vector<agg::rgba8>(2));
|
||
ginfo.shading.patch_colors[0][0] = curve_colors[0];
|
||
ginfo.shading.patch_colors[0][1] = curve_colors[1];
|
||
ginfo.shading.patch_colors[1][0] = curve_colors[3];
|
||
ginfo.shading.patch_colors[1][1] = curve_colors[2];
|
||
ginfo.shading.shading_type = ShadingInfo::CurveInterpolation;
|
||
}
|
||
return ginfo;
|
||
}
|
||
static GradientInfo get_tensor_curve(const std::vector<std::vector<Point>> &curve_poits,
|
||
const std::vector<std::vector<float>> &curve_parametrs,
|
||
const std::vector<std::vector<agg::rgba8>> &curve_colors,
|
||
bool parametric,
|
||
bool luminosity = false,
|
||
float t0 = 0.0f, float t1 = 1.0f)
|
||
{
|
||
GradientInfo ginfo;
|
||
|
||
ginfo.shading.patch = curve_poits;
|
||
|
||
ginfo.shading.f_type = ShadingInfo::UseNew;
|
||
ginfo.shading.function = ColorFunction<agg::rgba8>(256, t0, t1);
|
||
ginfo.luminocity = luminosity;
|
||
ginfo.continue_shading_f = false;
|
||
ginfo.continue_shading_b = false;
|
||
|
||
if (parametric)
|
||
{
|
||
ginfo.shading.patch_parameters = curve_parametrs;
|
||
ginfo.shading.shading_type = ShadingInfo::Parametric;
|
||
}
|
||
else
|
||
{
|
||
ginfo.shading.patch_colors = curve_colors;
|
||
ginfo.shading.shading_type = ShadingInfo::TensorCurveInterpolation;
|
||
}
|
||
return ginfo;
|
||
}
|
||
};
|
||
}
|
||
|
||
#endif
|