///Предоставляет базовые классы и интерфейсы.
unit Main;
uses System;
type
///Предоставляет метод CloneAs(): T.
ICloneableAs = interface(ICloneable)
function CloneAs(): T;
end;
type
///Объект, ограниченный снизу и сверху.
TBordered = abstract class
protected
_low, _high: real;
procedure TrySwap(var a, b: real);
begin
if a > b then
Swap(a, b);
end;
procedure setLow(value: real);
begin
_low := value;
TrySwap(_low, _high);
end;
procedure setHigh(value: real);
begin
_high := value;
TrySwap(_low, _high);
end;
public
///Нижняя граница.
property Low: real read _low write setLow;
///Верхняя граница.
property High: real read _high write setHigh;
end;
end.///Предоставляет интерполяторы.
unit Interpolators;
uses System, Main, Structures, Graphics;
type
///Функция, принимающая целое число входным параметром и возвращающая целое число.
TIntFunc = IntFunc;
///Функция, принимающая вещественное число входным параметром и возвращающая вещественное число.
TRealFunc = RealFunc;
type
///Интерполятор.
TInterpolator = class(TBordered)
private
_interpolatorFunc: TRealFunc;
_lowY, _highY: real;
_stepsCount: real;
_isNormalized: boolean;
_isInverted: boolean;
_resizeFactor: real;
procedure setLowY(value: real);
begin
_lowY := value;
TrySwap(_lowY, _highY);
end;
procedure setHighY(value: real);
begin
_highY := value;
TrySwap(_lowY, _highY);
end;
procedure setStepsCount(value: real);
begin
if value = 0 then
raise new ArgumentException('Количество шагов не может быть нулевым.');
_stepsCount := Abs(value);
end;
function getWidth() := _high - _low;
function getStep() := getWidth() / _stepsCount;
function getFunctionValues(): sequence of real;
begin
var step := getStep();
var current := _low;
while current < _high do
begin
var value := _interpolatorFunc(current);
if value < _lowY then
value := _lowY
else if value > _highY then
value := _highY;
yield value;
current += step;
end;
end;
public
///Интерполируемая функции.
property InterpolatorFunc: TRealFunc read _interpolatorFunc write _interpolatorFunc;
///Нижняя граница по оси Y.
property LowY: real read _lowY write setLowY;
///Верхняя граница по оси Y.
property HighY: real read _highY write setHighY;
///Количество шагов для указанного интервала интерполяции.
property StepsCount: real read _stepsCount write _stepsCount;
///Указывает инвертируются ли значения функции.
property IsInverted: boolean read _isInverted write _isInverted;
///Указывает нормализируются ли значения функции.
property IsNormalized: boolean read _isNormalized write _isNormalized;
///Коэффициент масштабирования функции относительно среднего ее значения по оси Y.
property ResizeFactor: real read _resizeFactor write _resizeFactor;
///Ширина - разность верхней и нижней границ по оси X.
property Width: real read getWidth;
///Шаг - разность верхней и нижней границ по оси Y.
property Step: real read getStep;
constructor(interpolatorFunc_: TRealFunc; low_, high_, stepCount_: real);
begin
InterpolatorFunc := interpolatorFunc_;
(Low, High) := (low_, high_);
(LowY, HighY) := (-10, 10);
StepsCount := stepCount_;
ResizeFactor := 1;
end;
///Возвращает максимальное значение функции на указанном диапазоне.
function Max() := getFunctionValues().Max();
///Возвращает минимальное значение функции на указанном диапазоне.
function Min() := getFunctionValues().Min();
///Возвращает среднее значение функции на указанном диапазоне.
function Average() := (Max() + Min()) / 2;
///Возвращает высоту функции.
function Height() := Max() - Min();
///Возвращает последовательность значений функции с шагом Step на указанном диапазоне интерполирования.
function FunctionValues(): sequence of real;
begin
Result := getFunctionValues().Select(x -> self.Average() + (x - self.Average()) * _resizeFactor);
if _isInverted then
Result := Result.Select(x -> 2 * self.Min() + self.Height() - x);
if _isNormalized then
Result := Result.Select(x -> (x - self.Min()) / self.Height());
end;
end;
///Объединение двух интерполяторов.
TInterpolatorsUnion = class
private
_first, _second: TInterpolator;
_influence: TInterpolator;
_fromFirstToSecond: boolean;
procedure TryRaise(value1, value2, value3: TInterpolator);
begin
if (value1.StepsCount <> value2.StepsCount) or (value2.StepsCount <> value3.StepsCount) then
raise new ArgumentException('Количество шагов трёх интерполяторов должно быть равно. [Установите изначально интерполяторы с одинаковым количеством шагов интерполяции - StepsCount.]');
end;
procedure setFirst(value: TInterpolator);
begin
TryRaise(value, _second, _influence);
_first := value;
end;
procedure setSecond(value: TInterpolator);
begin
TryRaise(_first, value, _influence);
_second := value;
end;
procedure setInfluence(value: TInterpolator);
begin
TryRaise(_first, _second, value);
_influence := value;
end;
public
///Первый интерполятор.
property First: TInterpolator read _first write setFirst;
///Второй интерполятор.
property Second: TInterpolator read _second write setSecond;
///Сила интерполяции от функции первого интерполятора к функции второго интерполятора (или наоборот).
property Influence: TInterpolator read _influence write setInfluence;
///Направление интерполяции.
property FromFirstToSecond: boolean read _fromFirstToSecond write _fromFirstToSecond;
constructor(first_, second_, influence_: TInterpolator);
begin
(_first, _second) := (first_, second_);
_influence := influence_;
TryRaise(_first, _second, _influence);
FromFirstToSecond := true;
end;
///Возвращает последовательность значений, полученных интерполяцией значений двух функций.
function Interpolate(): sequence of real;
begin
var (firstValues, secondValues) := (_first.FunctionValues().ToArray(), _second.FunctionValues().ToArray());
if not _fromFirstToSecond then
Swap(firstValues, secondValues);
var influenceValues := _influence.FunctionValues().ToArray();
for var i := 0 to Pred(firstValues.Count) do
yield firstValues[i] + (secondValues[i] - firstValues[i]) * influenceValues[i];
end;
end;
///Интерполятор в границах прямоугольника.
TPathInterpolator = class
private
_first, _second: TPoint;
_xInterpolator, _yInterpolator: TInterpolator;
procedure TryRaise(value1, value2: TInterpolator);
begin
if value1.StepsCount <> value2.StepsCount then
raise new ArgumentException('Количество шагов двух интерполяторов должно быть равно. [Установите изначально интерполяторы с одинаковым количеством шагов интерполяции - StepsCount.]');
end;
procedure setXinterpolator(value: TInterpolator);
begin
TryRaise(value, _yInterpolator);
_xInterpolator := value;
end;
procedure setYinterpolator(value: TInterpolator);
begin
TryRaise(value, _xInterpolator);
_yInterpolator := value;
end;
function getWidth() := _second.X - _first.X;
function getHeight() := _second.Y - _first.Y;
public
///Верхняя левая точка прямоугольника.
property First: TPoint read _first write _first;
///Нижняя правая точка прямоугольника.
property Second: TPoint read _second write _second;
///Интерполятор координат по оси X.
property Xinterpolator: TInterpolator read _xInterpolator write setXinterpolator;
///Интерполятор координат по оси Y.
property Yinterpolator: TInterpolator read _yInterpolator write setYinterpolator;
///Ширина прямоугольника.
property Width: real read getWidth;
///Высота прямоугольника.
property Height: real read getHeight;
constructor(first_, second_: TPoint; xInterpolator_, yInterpolator_: TInterpolator);
begin
(First, Second) := (first_, second_);
(_xInterpolator, _yInterpolator) := (xInterpolator_, yInterpolator_);
TryRaise(_xInterpolator, _yInterpolator);
end;
///Возвращает путь, полученный интерполяцией в границах прямоугольника, на основе двух заданных интерполяторами функций.
function FunctionValues(): sequence of TPoint;
begin
var (x, y) := (_xInterpolator.Low, _yInterpolator.Low);
var (isInvertedX, isInvertedY) := (_xInterpolator.IsNormalized, _yInterpolator.IsNormalized);
(_xInterpolator.IsNormalized, _yInterpolator.IsNormalized) := (true, true);
var (xValues, yValues) := (_xInterpolator.FunctionValues().ToArray(), _yInterpolator.FunctionValues().ToArray());
for var i := 0 to Pred(xValues.Count) do
yield new TPoint(_first.X + getWidth() * xValues[i], _first.Y + getHeight() * yValues[i]);
(_xInterpolator.IsNormalized, _yInterpolator.IsNormalized) := (isInvertedX, isInvertedY);
end;
end;
end.