Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
32
Добавлен:
28.06.2014
Размер:
29 Кб
Скачать
☆
unit Unit4;

interface
  uses classes, graphics, types, controls;
  type
    TMouseButtonEx = (mbLeft, mbRight, mbMiddle, mbNone);
    CRunge = class of TRunge;

    T2Rect = record
      EXa, EXb: double;
      EYa, EYb: double;
    end;

    TRealArr = array of double;
    PResArr = ^TResArr;

    Tfun = function (x: double; y: TRealArr): double;  //Тип-функция переводящая [double] -> double
    TfunReal = function (x: double): double;  //Тип-функция переводящая [double] -> double
    TarrFun = array of TFun;  //Массив функций

    TRes = record  //Одна запись в результате
      x: double; //Абсцисса точки
      arr: TRealArr;  //Массив одрдинат для каждой функции
    end;

    TResArr = array of TRes;  // Массив таких значений - сам резуьтат

    //Класс для метода Рунге-Кутты 4 порядка.
    TRunge = class
    private
      Erange: integer;  //кол-во функций в системе
      Estart: TRealArr; //Начальные значения
      EFirst, ELast: double; //Начальное и конечное значение по оси t
      Eeps: double; //Точность
      Efun: TArrfun; //массив функций
      EArr: TResArr; //Массив значений функции в точках, больше 0.
      EArrNeg: TResArr; //Массив значений функции в точках, меньших 0
      EGetInd: integer; //Внутренняя переменная - для быстрого поиска нужного значения
      procedure SetRange(const Value: integer); virtual;//Установить количество функций в системе
      function GetStart(Index: Integer): double; //Получить начальное значений для функции index
      procedure SetStart(Index: Integer; const Value: double);//Установить начальное значение value для функции index
      function GetRes(X: double; index: integer): double; //Узнать значение функции index в точке x
      function GetResInd(X: double): TRealArr; //Узнать значение всех функций в точке x
      function GetCount: integer;   //Узнать общее количество точек
      function GetLeftInd: integer; //Узнать номер самой левой точки в массива
      function GetRightInd: integer; //Узнать номер самой правой точки
      function Value(const x: real; const y: TRealArr; const h: real): TRealArr; //Вычисление значения в следующей точке методом РК-4
      function Value5(const x: real; const y: TRealArr; const h: real): TRealArr;//Вычисление значения в следующей точке методом РК-5
      procedure SetEps(const Value: double); virtual; //Установить значение точности
      function calc(vlast: double; veps: double): TRes; overload; virtual; //Процедура вычисления значения в точке vlast с точностью veps
    public
      property LeftInd: integer read GetLeftInd;   //Левый индекс
      property RightInd: integer read GetRightInd; // Правый индекс в массиве точек
      function GetInd(v: integer; n: integer): double; //Узнать значение функции v в точке n
      property Count: integer read GetCount; //Доступ к количеству точек в результате
      property Arr[X: double]: TRealArr read GetResInd; default; //Доступ к значениям функции в точке x
      property ArrInd[X: double; index: integer]: double read GetRes; //Доступ к значению конкретной функции index в точке x
      property range: integer read Erange write SetRange; //Доступ к количеству функций
      property Start[Index: integer]: double read GetStart write SetStart; //Доступ к начальным значениям
      property First: double read Efirst write EFirst; //Начальное значение по оси t
      property Last: double read ELast write ELast; //Конечное значение по оси t
      property eps: double read EEps write SetEps; //Точность вычисления
      property Fun: TarrFun read EFun write EFun;//Доступ к массиву функций
      constructor Create; virtual;
      function Calcat(vfirst, vlast, veps: double): boolean;  //Вычислить значение на отрезке с точностью
      procedure ProcessMessages;
      function CheckDelat(n: integer; f: TFunReal): double; //Проверить отклонение полученной функции от реальной.
    end;
    type
        TCanv = record
          ECanv: TCanvas;
          EWidth, EHeight: integer;
        end;
        TMouse = record
    //      mouseflag: boolean;
          mousebk: TPoint;
          mousestep: TPoint;
          mouseRect: TRect;
          mouseBtn: TMouseButtonEx;
        end;


    TGraphicsRunge =  class(TRunge)
      private
        EMouse: TMouse;
        ebmp: TBitMap;
        Erect: T2Rect;
        ECanv: TCanv;
        arr: array of TRealArr;
        EVisible: Array of boolean;
        Escaley, Escalex: double;
        procedure SetRange(const Value: integer); override;
        function GetIndex(X: double): integer;
        function GetSize: TPoint;
        procedure SetRect(const Value: T2Rect);
        procedure SetCanvas(const Value: TPoint);
        procedure SetVisible(Index: Integer; const Value: boolean);
        function GetVisible(index: integer): boolean;
        property EWidth: integer read ECanv.ewidth;
        property EHeight:integer read ECanv.eheight;
        property ExA: double read ERect.ExA;
        property EYA:double read ERect.EYA;
        property ExB: double read ERect.ExB;
        property EYB:double read ERect.EYB;
        procedure SetEps(const Value: double); override;
      public
        procedure Redraw;
        procedure ReCreateArr;
        constructor Create; override;
        constructor Assign(v:CRunge);
        property Canvas: TCanvas read ECanv.ECanv write ECanv.ECanv;// write SetCanvas;
        property Size: TPoint read GetSize write SetCanvas;
        property Rect: T2Rect read Erect write  SetRect;
        property Visible[index: integer]: boolean read GetVisible write SetVisible;
        property Scaley: double read  Escaley;
        property ScaleX: double read  Escalex;

        procedure MouseMove(Shift: TShiftState; X, Y: Integer);
        procedure MouseLeave;
        procedure MouseClick;
        procedure MouseUp( Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
        procedure MouseDown( Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
     end;


    //Класс для исходной задачи
    TProg1 = class(TRunge)
    public
      constructor Create; override; //В конструкторе описываем те входные данные, которые требуется использовать в конкретной задаче
    end;

    //Два класса для тестовых примеров
    TProg2 = class(TRunge)
    public
      constructor Create; override;
    end;

    TProg3 = class(TRunge)
    public
      constructor Create; override;
    end;

  function SRect(vXa, vYa, vXb, vYb:double): T2rect;
implementation
  uses unit2,  sysutils, math, wintypes;

function SRect(vXa, vYa, vXb, vYb:double): T2rect;
begin
  result.EXa:=vXa;
  result.eyA:=vYa;
  result.EXb:=vXb;
  result.eyb:=vYB;
end;
  function sin(x: double): double;
  begin
    result:=system.Sin(x);
  end;
  function exp1(x: double): double;
  begin
    result:=system.Exp(x)+1;
  end;

{ TRunge }
//Конструктор
function TRunge.Calcat(vfirst, vlast, veps: double): boolean;
var t1,t2: TDateTime;
  Hour, Min, Sec, MSec: Word;
begin
    setlength(EArr, 1);  //Устанавливаем в результирующий список значений функции начальные значения
    EArr[0].x:=First;
    EArr[0].arr:=Estart;
    setlength(EArrNeg, 1);
    EArrNeg[0].x:=First;
    EArrNeg[0].arr:=Estart;
    form2.lblTime.Caption:='Вычисление...';
    t1:=GetTime;
    calc(vlast, 0);
    calc(vfirst, 0);
    result:=(EArr[High(EArr)].x >= vLast) and (EArrNeg[High(EArrNeg)].x <= vfirst);
    t2:=GetTime;
    DecodeTime(t2-t1,Hour, Min, Sec, MSec);
    form2.lblTime.Caption:=inttostr(sec*1000+Msec)+' ms';

end;

function TRunge.CheckDelat(n: integer; f: TFunReal): double;
var i: integer;
begin
  result:=abs(f(Earr[0].x) - Earr[0].arr[n]);
  for i := 1 to high(EArr)-2 do
    result:=max(result,abs(f(Earr[i].x) - Earr[i].arr[n]));
  for i := 1 to high(EArrNeg)-2 do
    result:=max(result,abs(f(EArrNeg[i].x) - EArrNeg[i].arr[n]));
end;

constructor TRunge.Create;
begin
  setlength(EArr, 1);  //Устанавливаем в результирующий список значений функции начальные значения
  EArr[0].x:=First;
  EArr[0].arr:=Estart;
  setlength(EArrNeg, 1);
  EArrNeg[0].x:=First;
  EArrNeg[0].arr:=Estart;
end;


function TRunge.GetCount: integer;
begin
  result:=length(EArr)+length(EArrNeg)-1; //Количество точек равно сумме точек, с абсциссой больше нуля и меньше 0
end;

//Узнать значение функции в точке с номером v функции n
function TRunge.GetInd(v, n: integer): double;
begin
  result:=0;
  if n > range then exit; // Если такой функции нет, то выходим.
  if v < length(EArrNeg) then //Если такая функция есть, то рассматриваем варианты, из какого массива брать результат
    if n = 0 then
      result:=Earrneg[high(EArrNeg)-v].x
    else
      result:=Earrneg[high(EArrNeg)-v].arr[n-1]
  else if v < GetCount then
    if n = 0 then
      result:=Earr[v-length(EArrNeg)].x
    else
      result:=Earr[v-length(EArrNeg)].arr[n-1]
  else
    raise Exception.Create('Неверный индекс массива. Getindex('+inttostr(v)+','+inttostr(n)+')');
end;

function TRunge.GetLeftInd: integer;
begin
  result:=high(EArrNeg);
end;

function TRunge.GetRes(X: double; index: integer): double;
begin
  if index in [0..range-1]  then
    result:=GetResInd(x)[index]
  else
    raise Exception.Create('Неверный индекс массива. GetRes('+floattostr(x)+','+inttostr(index)+')');
 end;

//Результат - набор значений ординат результирующих функций в точке X
function TRunge.GetResInd(X: double): TRealArr;
var left, right, t: integer;
  i: integer;
  Arr: TResArr;
begin
  if x>=EFirst then //Выбираем массив, в котором будем искать нужное значение
    Arr:=EArr
  else
    Arr:=EArrNeg;
  //Массив упорядочен, поэтому будем искать значение бинарным посиком по обсцыссе
  //ПОпробуем на снове EGetInd локализовать нужное нам значение
  if  (EGetInd-5 <= high(Arr)) and (abs(Arr[EGetInd-5].x) < abs(x))  then
    left:=EGetInd-5
  else
    left:=0;
  if  (EGetInd+5 <= high(Arr)) and (abs(Arr[EGetInd+5].x) > abs(x))  then
    right:=EGetInd+5
  else
    right:=high(Arr);

  //left и right - границы отрезка.
  while left < right-1 do begin
    t:= (left+right) div 2;
    if abs(Arr[t].x) < abs(x) then
      left:=t
    else if Arr[t].x = x then begin
      right:=t;
      left:=t;
    end else begin
      right:=t;
    end;
  end;
  //Нашли отрезок наименьшей длины, на котором лежит нужный нам результат
  //Представим что функция линейна на этом отрезке
  setlength(Result, Erange);
  if right <> left then
    for i := 0 to ERange-1 do
      result[i]:=(Arr[right].arr[i]-Arr[left].arr[i])/(right-left)*x+Arr[left].arr[i]
  else
    for i := 0 to ERange-1 do
      result[i]:=Arr[right].arr[i];
  //EGetInd присвоим значение левой границы, чтобы при следующем поиске  было легче искать точку.
  EGetInd:=left;
end;

function TRunge.GetRightInd: integer;
begin
  result:=High(EArr)+length(EArrNeg);
end;

//Вернуть начальное значение функции index
function TRunge.GetStart(Index: Integer): double;
begin
  if (0<=index) and (index <= range-1) then
    result:=Estart[index]
  else
    raise Exception.Create('Неверный индекс массива. GetStart('+inttostr(index)+')');
end;


procedure TRunge.ProcessMessages;
var
  Msg: TMsg;
  lResult: boolean;
begin
  lResult := true;
  while lResult do begin
    lResult := false;
    if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin
      lResult := true;
      if Msg.Message <> 3 then begin
        TranslateMessage(Msg);
        DispatchMessage(Msg);
      end;
    end;
  end;
end;

//Усатновить количествой функций
procedure TRunge.SetEps(const Value: double);
begin
  EEps := Value;
end;

procedure TRunge.SetRange(const Value: integer);
begin
  Erange:=Value;
  setlength(Estart, Erange);
  setlength(Efun, Erange);
end;

//Установить начальное значнеие value для функции index
procedure TRunge.SetStart(Index: Integer;   const Value: double);
begin
  if (0<=index) and (index <= range-1) then
    Estart[index] :=value
  else
    raise Exception.Create('Неверный индекс массива. SetStart('+inttostr(index)+','+floattostr(value)+')');
end;



  //Увеличить значнеие каждого элемента массива на eps
  function inc(y: TRealArr; eps: double): TRealArr;
  var i: integer;
  begin
    setlength(result, length(y));
    for i := 0 to High(y) do
      result[i]:=y[i]+eps;
  end;

  //Скопировать массив а в масисв b
procedure assign(const a: TRealArr; out b: TRealArr);
var i: integer;
begin
  setlength(b, length(a));
  for i := 0 to high(b) do
    b[i]:=a[i];
end;

//Вычисленние одного шага методом Р-К 4
function TRunge.Value(const x: real; const y: TRealArr; const h: real): TRealArr;
var i: integer; //счетчики
  k: array of TRealArr;
begin
  setlength(k, 4, Erange);
  SetLength(Result, Erange);
    for i:=0 to Erange - 1 do k[0, i]:=Efun[i](x, y);
    for i:=0 to Erange - 1 do k[1, i]:=Efun[i](x+h/2, inc(y,h*k[0, i]/2));
    for i:=0 to Erange - 1 do k[2, i]:=Efun[i](x+h/2, inc(y,h*k[1, i]/2));
    for i:=0 to Erange - 1 do k[3, i]:=Efun[i](x+h, inc(y,h*k[2, i]));
    for i:=0 to Erange - 1 do result[i]:=y[i]+h*(k[0, i] + 2* k[1, i]+ 2*k[2, i]+ k[3, i])/6;
end;

function TRunge.Value5(const x: real; const y: TRealArr; const h: real): TRealArr;
var i: integer; //счетчики
  k: array of TRealArr;
begin
  setlength(k, 6, Erange);
  SetLength(Result, Erange);
    for i:=0 to Erange - 1 do begin
      k[0, i]:=EFun[i](x, y);
      k[1, i]:=EFun[i](x + 1/4*h,   inc(y, h*k[0,i]/4));
      k[2, i]:=EFun[i](x + 3/8*h,   inc(y, h*(3/32*k[0,i] + 9/32*k[1,i])));
      k[3, i]:=EFun[i](x + 12/13*h, inc(y, h*(1932/2197*k[0,i] -  7200/2197*k[1,i] +  7296/2197*k[2,i])));
      k[4, i]:=EFun[i](x + h,       inc(y, h*(439/216*k[0,i] - 8*k[1,i] +  3680/513*k[2,i] - 845/4104*k[3,i])));
      k[5, i]:=EFun[i](x + h/2,     inc(y, h*(- 8/27*k[0,i] + 2*k[1,i] - 3544/2565*k[2,i] + 1859/4104*k[3,i] - 11/40*k[4,i])));
//      result[i] := y[i] + h*(25/216*k[0,i] + 1408/2565*k[2,i] + 2197/4104*k[3,i] - k[4,i]/5);
      result[i] :=y[i] + h*(16/135*k[0,i] + 6656/12825*k[2,i] + 28561/56430*k[3,i] +2/55*k[4,i]-9/50*k[5,i]);
    end;

end;

  //Проверка,
  function checkeps(const a,b: TRealArr): double;
  var i: integer;
  begin
    if length(a) <> length(b) then
      raise Exception.Create('Неверная длина массива. calc.CheckEps: a-'+inttostr(length(a))+', b-'+inttostr(length(b)));
    result:=abs(a[0]-b[0]);
    for i := 1 to high(a) do
      result:=max(result, abs(a[i] - b[i]));
  end;

    //Выполнение одного шага, со всеми проыверками

function TRunge.calc(vlast, veps: double): TRes;
var
  h, hmin: double;
  Arr: PResArr;
  procedure Step;
  var tmp, tmp1, tmp2: TRes;
    i: integer;
    delta: double;
  begin
    //Текущее значение функции
    //x    x+h/2      x+h = x+h/2+h/2
    tmp.arr:=value(Arr^[High(Arr^)].x,Arr^[High(Arr^)].arr,h);
    tmp.x:=Arr^[High(Arr^)].x+h;
//    tmp1.arr:=value5(Arr^[High(Arr^)].x,Arr^[High(Arr^)].arr,h/2);
//    tmp1.x:=Arr^[High(Arr^)].x+h/2;
//    tmp2.arr:=value5(tmp1.x,tmp1.arr,h/2);
    tmp2.arr:=value5(Arr^[High(Arr^)].x,Arr^[High(Arr^)].arr,h);
    tmp2.x:=tmp.x;
    //Если функция по точности нам подходит
    delta:=checkeps(tmp2.arr,tmp.Arr)*abs(ELast-EFirst)/abs(hmin);
    if delta < Eeps then begin
      hmin:=min(hmin, abs(h));
      //То добавляем её в результрующий массив
      setlength(Arr^, length(Arr^)+1);
      setlength(Arr^[High(Arr^)].Arr, Erange);
      for i := 0 to Erange-1 do
        Arr^[High(Arr^)].Arr[i]:=tmp.arr[i];//+(tmp2.arr[i]-tmp.arr[i])/31;
      Arr^[High(Arr^)].x:=tmp2.x;
      //Если точность хорошая, то увеличиваем длину шага
      if delta < Eeps/1000 then
        h:=2*h;
    end else begin
      //Если точность не достигнута, то уменьшаем шаг
      h:=h/2;
    end;
  end;
begin
  Last:=vlast;
  if veps > 0 then
    Eeps:=veps;
  h:=(Elast-Efirst)/10;
  hmin:=abs(h);
    if Elast > EFirst then begin
    Arr:=@Earr;
    while Arr^[High(Arr^)].x < last  do begin
      step;
    end
  end else begin
    Arr:=@EarrNeg;
    while Arr^[High(Arr^)].x > last  do begin
      step;
    end;
  end;


  result:=Arr^[High(Arr^)];
end;




{ TProg1 }
//x  = y[1]
//x` = y[0]
//y =  y[3]
//y` = y[2]
function fun1_1(x: double; y: TRealArr): double;
const mu = 1/82.45;
      mun = 1-mu;
begin
  result:=2*y[2]+y[1] - mun*(y[1]+mu)/power(sqrt(sqr(y[1]+mu)+sqr(y[3])),3) - mu*(y[1]-mun)/power(sqrt(sqr(y[1]-mun)+sqr(y[3])),3);  //+ c мю
end;

function fun1_2(x: double; y: TRealArr): double;
begin
  result:=y[0];
end;

function fun1_3(x: double; y: TRealArr): double;
const mu = 1/82.45;
      mun = 1-mu;
begin
  result:=-2*y[0]+y[3]-mun*y[3]/power(sqrt(sqr(y[1]+mu)+sqr(y[3])),3)-mu*y[3]/power(sqrt(sqr(y[1]-mun)+sqr(y[3])),3);
end;

function fun1_4(x: double; y: TRealArr): double;
begin
  result:=y[2];
end;


//Основная задача
constructor TProg1.Create;
begin
  range:=4;
  fun[0]:=fun1_1;
  fun[1]:=fun1_2;
  fun[2]:=fun1_3;
  fun[3]:=fun1_4;
  start[0]:=1.2;
  start[1]:=0;
  start[2]:=0;
  start[3]:=-0.4;//..1.0495;
  First:=0;
  inherited;
end;




{ TProg2 }

{ TProg2 }

function fun2_1(x: double; y: TRealArr): double;
begin
  result:=y[1];
  //y[1] = y`[0];
end;

function fun2_2(x: double; y: TRealArr): double;
begin
  result:=y[2];
  //y[2] = y`[1] = y``[0]
end;

function fun2_3(x: double; y: TRealArr): double;
begin
  result:=-y[1];
  //y`[2] = y``[1] = y```[0]
end;


//y = sin(x)
//y[0] = y =        sin(x)
//y[1] = y` = y`[0] = cos(x)
//y[2] = y`` = y`[1] = -sin(x)
//y``` = y``[1] = y`[2] = -cos(x) = -y[1]
//y``` = -y`
//t`` = -t   t(0) = 1   t(1)

constructor TProg2.Create;
begin
  range:=3;
  fun[0]:=fun2_1;
  fun[1]:=fun2_2;
  fun[2]:=fun2_3;
  start[0]:=0;
  start[1]:=1;
  start[2]:=0;
  First:=0;
  inherited;
end;

{ TProg3 }


function fun3_1(x: double; y: TRealArr): double;
begin
  result := y[1];
end;

function fun3_2(x: double; y: TRealArr): double;
begin
  result :=  3*exp(x)+8 + 6*y[1] - 8*y[0];
end;

//y`` - 6y`+8*y = 3*exp(x) + 8;
// y = c1*exp(4x) + c2*exp(2x) + exp(x)+1
//y` = 4*c1*exp(4x) + 2*c2*exp(2x) + exp(x)
//y`` = 16c1 exp(4^x) + 4*c2 * exp(2x) + exp(x);
//y(0) = c1+c2+1+1 = 2
//y`(0) = 4c1+2c2+1 = 1

constructor TProg3.Create;
begin
  range:=2;
  fun[0]:=fun3_1;
  fun[1]:=fun3_2;
  start[0]:=2;
  start[1]:=1;
  First:=0;
  inherited;
end;

{ TGraphicsRunge }

constructor TGraphicsRunge.Assign(v: CRunge);
var i: integer;
  g: TRunge;
begin
  create;
  g:=v.Create;
  range:=g.Erange; //кол-во функций в системе
  for i := 0 to Erange-1 do
    Estart[i]:=g.EStart[i];
  EFirst:=g.EFirst;
  ELast:=g.ELast; //Начальное и конечное значение по оси t
  for i := 0 to Erange-1 do
    Efun[i]:=g.Efun[i];//массив функций
  g.Free;
end;

constructor TGraphicsRunge.Create;
begin
  //inherited;
 // EMouse.mouseflag:=false;
  EMouse.mouseBtn:=mbNone;
  Erect.EXa:=Efirst-1;
  Erect.EXb:=EFirst+1;
  Erect.EYa:=1;
  Erect.EYb:=-1;
  EEps:=0.01;
//  calc(Exa, 0.1);
//  calc(Exb, 0.1);
  ebmp:=graphics.TBitmap.Create;
end;

function TGraphicsRunge.GetIndex(X: double): integer;
var left, right, t: integer;
  Arr: TResArr;
begin
  if x>=EFirst then //Выбираем массив, в котором будем искать нужное значение
    Arr:=EArr
  else
    Arr:=EArrNeg;
  //Массив упорядочен, поэтому будем искать значение бинарным посиком по абсцыссе
  left:=0;
  right:=high(Arr);
  //left и right - границы отрезка.
  while left < right-1 do begin
    t:= (left+right) div 2;
    if abs(Arr[t].x) < abs(x) then
      left:=t
    else if Arr[t].x = x then begin
      right:=t;
      left:=t;
    end else begin
      right:=t;
    end;
  end;
  result:=left;
end;

function TGraphicsRunge.GetSize: TPoint;
begin
  result:=Point(ECanv.EWidth, ECanv.EWidth);
end;

function TGraphicsRunge.GetVisible(index: integer): boolean;
begin
  if index < length(EVisible) then
    result:=EVisible[index]
  else
    result:=false;
end;

procedure TGraphicsRunge.MouseClick;
begin

end;

procedure TGraphicsRunge.MouseDown( Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 // EMouse.mouseflag:=true;
  EMouse.mousebk:=Point(X,y);
  EMouse.mousestep:=Point(X,y);
  EMouse.mouseBtn:=TMouseButtonEx(Button);
end;

procedure TGraphicsRunge.MouseLeave;
begin
          ECanv.ECanv.Draw(0,0, ebmp);
end;

procedure TGraphicsRunge.MouseMove(Shift: TShiftState; X, Y: Integer);
var i: integer;
Vx, VY: double;
Text: string;
begin
  with Emouse do begin
    case mouseBtn of
      mbLeft:
        begin
          Rect:=SRect(Rect.EXa+(-X+mousestep.X)*scalex,Rect.EYa+(Y-mousestep.Y)*scaleY,Rect.EXB+(-X+mousestep.X)*scalex,Rect.EYB+(Y-mousestep.Y)*scaleY);
          mousestep:=Point(x, Y);
        end;
      mbRight:
        begin
          mousestep:=Point(x, Y);
          ECanv.ECanv.Draw(0,0, ebmp);
          ECanv.ECanv.Brush.Style:=bsClear;
          ECanv.ECanv.Pen.Color:=clGray;
          ECanv.ECanv.Pen.Style:=psDash;
          if EMouse.mouseBtn = mbRight then
            ECanv.ECanv.Rectangle(EMouse.mousebk.X,EMouse.mousebk.y,EMouse.mousestep.x, EMouse.mousestep.y);
          ECanv.ECanv.Pen.Style:=psSolid;
        end;
      else
        begin
          VX:= X*scalex;
          VY:= Y*scaley;
          Canvas.Draw(0,0,ebmp);
          canvas.Pen.Color:=clBlack;
          for i := 0 to Range-1 do
            if abs((EYb-arr[i, X])/scaley - y) < 7 then begin
              case i of
               0:    canvas.Pen.Color:=clRed;
               1:    canvas.Pen.Color:=clGreen;
               2:    canvas.Pen.Color:=clBlue;
               3:    canvas.Pen.Color:=clPurple;
              end;
              canvas.Brush.Color:=canvas.Pen.Color;
              Canvas.Ellipse(x-3,y-3, x+3, y+4);
              break;
            end;
          canvas.moveto(0,y);
          canvas.lineto(EWidth,y);
          canvas.moveto(x,0);
          canvas.lineto(x,EHeight);
          canvas.Brush.Color:=ColorToRGB(clCream) ;
          text:= floattostrf(Vx+ExA, ffGeneral,round(-log10(eps))+1,round(-log10(eps))+1) + ' ' + floattostrf(eyb-VY, ffGeneral,round(-log10(eps))+1,round(-log10(eps))+1);
          canvas.Rectangle(x,y,x+canvas.TextWidth(Text)+5, y-canvas.TextHeight(Text)-3);
          Canvas.TextOut(X+2,Y-canvas.TextHeight(Text)-2, text);
        end;

    end;
  end;


end;

procedure TGraphicsRunge.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if EMouse.mouseBtn = mbRight then begin
    if (abs(EMouse.mousebk.X-EMouse.mousestep.x ) < 10) and (abs(EMouse.mousebk.y-EMouse.mousestep.y ) < 10) then begin
      Rect:=SRect((3*ExA - exb)/2,(3*EYA - eYB)/2,(3*ExB - exA)/2,(3*EYB - eYA)/2);
    end else begin
      Rect:=SRect(EMouse.mousebk.X*scalex+exa,eYb-EMouse.mousebk.y*scaley,EMouse.mousestep.x*scalex+exa,eYB- EMouse.mousestep.y*scaley);
    end;

  end;


  EMouse.mouseBtn:=mbNone;

end;


procedure TGraphicsRunge.ReCreateArr;
var
  i: integer;
  index: integer;
  j: integer;
  x: double;
begin
//  Определим масштаб
  try
  if exa >= Efirst then begin
    index:=GetIndex(exa); // из EArr
    for i := 0 to EWidth do begin // I - точка на рисунке
      X:=exa +  (exb-exa) / Ewidth * i; //Cоответствующая её точка x
      for j := index to high(EArr) do
        if EArr[j].x > X  then break;
      //Возбмем значение в точке j-1
      index:=j-1;
      for j := 0 to erange-1 do
        arr[j,i]:=EArr[index].arr[j]+ (EArr[index-1].arr[j]-EArr[index].arr[j])/(EArr[index-1].x-EArr[index].x) * (X - EArr[index].x);
    end;
  end else begin
    index:=GetIndex(exa); // из EArrNeg
    setlength(arr, Erange, EWidth+1);
    for i := 0 to EWidth do begin // I - точка на рисунке
      X:=exa +  (exb-exa) / Ewidth * i; //Cоответствующая её точка x
      for j := index downto 0 do
        if EArrNeg[j].x > X  then break;
      //Возбмем значение в точке j-1
      if j = -1 then
        break;
      index:=j+1;
      for j := 0 to erange-1 do
        arr[j,i]:=EArrNeg[index-1].arr[j]+ (-EArrNeg[index-1].arr[j]+EArrNeg[index].arr[j])/(EArrNeg[index-1].x-EArrNeg[index].x) * (EArrNeg[index-1].x-X);
    end;
    index:=0;
    for i := i to EWidth do begin // I - точка на рисунке
      X:=exa +  (exb-exa) / Ewidth * i; //Cоответствующая её точка x
      for j := index to high(EArr) do
        if EArr[j].x > X  then break;
      //Возбмем значение в точке j-1
      index:=j-1;
      if index+1 > high(EArr) then break;
      for j := 0 to erange-1 do
        arr[j,i]:=EArr[index].arr[j]+ (EArr[index+1].arr[j]-EArr[index].arr[j])/(EArr[index+1].x-EArr[index].x) * (X - EArr[index].x);
    end;
  end;
  except

  end;
end;

procedure TGraphicsRunge.Redraw;
var canv: Tcanvas;
  i, i0: integer;
  scalex: double;
  j, h, o: integer;
  k: double;
  txt:string;
begin
  try
  scalex:=escalex;
  canv:=ebmp.Canvas;
  canv.Pen.Color:=clBlack;
  canv.Pen.Width:=1;
  canv.Rectangle(0,0,Ewidth, EHeight);
//--------------------
    if sign(EXb)-sign(EXa) >= 1 then begin
      j:=round(-EWidth * eXa/(eXb-eXa)); //Cоответствующая её точка x
      canv.moveTo(j, 0);
      canv.lineTo(j, EWidth);
      for i := 1 to 4 do begin
        i0:=i*EHeight div 5;
        canv.Ellipse(j-5, i0-5, j+5, i0+5);
        canv.TextOut(j-35,i0+5, FloatToStrF(eYa+(eYb-eYa)*(5-i)/5, ffGeneral, 4, 4));
      end;
    end;
    if sign(Eyb)-sign(EYa) >= 1 then begin
      j:=round(EHeight * eYa/(eYb-eYa)+EHeight); //Cоответствующая её точка x
      canv.moveTo(0, j);
      canv.lineTo(EWidth,j);
      for i := 1 to 4 do begin
        i0:=i*EWidth div 5;
        canv.Ellipse(i0-5, j-5, i0+5, j+5);
        canv.TextOut(i0-5,j+5, floattostrF(exa+(exb-exa)*i/5, ffGeneral, 4, 4));
      end;
    end;
    k:=EHeight/(EYb-EYa);
    for j := 0 to range-1 do begin
      if not EVisible[j] then Continue;
      case j of
       0:    canv.Pen.Color:=clRed;
       1:    canv.Pen.Color:=clGreen;
       2:    canv.Pen.Color:=clBlue;
       3:    canv.Pen.Color:=clPurple;
      end;
      canv.Pen.Width:=2;
      canv.moveTo(0, round((eYb-arr[j, 0])*k));
      for i := 0 to EWidth do begin
        canv.lineTo(i, round((eyb - arr[j, i])*k));
      end;
    end;
    canv.Pen.Color:=clBlack;
    canv.Pen.Width:=1;
    j:=15;
    h:=(ewidth) div j;
    o:=(ewidth) mod j div 2;
    canv.Font.Height:=8;
    for i := 2 to  j-2  do begin
      canv.moveto(o+i*h, 2);
      canv.lineto(o+i*h, 8);
      txt:=floattostrf((o+i*h)*scalex+ExA, ffGeneral,round(-log10(eps)),round(-log10(eps)));
      canv.TextOut(o+i*h-canv.TextWidth(txt) div 2, 10, txt);
      canv.moveto(o+i*h, EHeight-2);
      canv.lineto(o+i*h, EHeight-8);
      canv.TextOut(o+i*h -canv.TextWidth(txt) div 2, EHeight-8-canv.TextHeight(txt), txt);
    end;
    j:=15;
    h:=(EHeight) div j;
    o:=(EHeight) mod j div 2;
    canv.Font.Height:=8;
    for i := 2 to  j-2  do begin
      canv.moveto(2,o+i*h);
      canv.lineto(8,o+i*h);
      txt:=floattostrf(-(o+i*h)*scaley+EYB, ffGeneral,round(-log10(eps)),round(-log10(eps)));
      canv.TextOut(11,o+i*h-4, txt);
      canv.moveto(EWidth-3,o+i*h);
      canv.lineto(EWidth-9,o+i*h);
      canv.TextOut(EWidth-10-canv.TextWidth(txt),o+i*h-4, txt);
    end;
    ECanv.ECanv.Draw(0,0, ebmp);

  except
  end;
end;



procedure TGraphicsRunge.SetCanvas(const Value: TPoint);
begin
  if EHeight <> 0 then
    EscaleY:=(eYB-eYA)/EHeight;
  if Ewidth <> 0 then
    Escalex:=(exB-exA)/Ewidth;
  ECanv.EWidth:=Value.X;
  setlength(arr, Erange, EWidth+1);
  ECanv.EHeight:=Value.y;
  ebmp.Width:=Value.X;
  ebmp.Height:=Value.y;
end;

procedure TGraphicsRunge.SetEps(const Value: double);
begin
  if Value > 0 then begin
    EEps:=value;
    calcat(Exa, Exb, 0);
  end;
end;

procedure TGraphicsRunge.SetRange(const Value: integer);
var i: integer;
begin
  inherited;
  setlength(arr, Erange, EWidth+1);
  setlength(EVisible, Erange);
  for i :=  0 to ERange-1 do
    EVisible[i]:=true;
end;

procedure TGraphicsRunge.SetRect(const Value: T2Rect);
var p: T2Rect;
begin
  p:=Value;
  if p.Exa > p.Exb then begin
    p.Exa:=value.EXb;
    p.EXb:=value.EXa;
  end;
  if p.EYa > p.EYb then begin
    p.EYa:=value.EYb;
    p.EYb:=value.EYa;
  end;
  if EHeight <> 0 then
    EscaleY:=(p.EYb-p.EYa)/EHeight;
  if Ewidth <> 0 then
    Escalex:=(p.EXB-p.EXa)/Ewidth;
 // if (p.EXa < EXa) or (p.EXb > EXb)  then begin
    if calcat(p.EXa, p.EXb, 0) then begin
      Erect:=p;
     ReCreateArr;
     redraw;
//    end else
//       Erect:=p;
//  end else begin
//      Erect:=p;
//     ReCreateArr;
//     redraw;
  end;

end;

procedure TGraphicsRunge.SetVisible( Index: Integer;  const Value: boolean);
begin
  if Index <= high(EVisible) then begin
    EVisible[Index]:=value;
    Redraw;
  end;
end;

{ TRes }

//procedure TRes.Copy(v: TRes);
//var i: integer;
//begin
//  x:=v.x;
//  assign(arr,v.arr));
//end;

end.

Соседние файлы в папке Runge