координат рядка-заголовка та стовпця заголовка (верхнього лівого кута
таблиці з заголовками): HeadColNumInGrid і HeadRowNumInGrid.}
Var CurFloatVal:TWorkFloat; CurElmType:THeadLineElmType;
Begin
CurElmType:=CurHeadCol[SRow].ElmType;
CurFloatVal:=0;
Try {Пробуємо розпізнати число:}
CurFloatVal:=StrToFloat (CurGrid. Cells [Self.CHeadColNum,
SRow+bc_LTaskRowsBeforeVars+Self.CHeadRowNum]);
CurElmType:=bc_Number; {якщо число розпізналося, то це число}
Except{Якщо рядок не інтерпретується як число, але комірка вважалася
такою, що містить число або змінну, то вважаємо його назвою функції
(бо це не число, і не повинно бути змінною – усі змінні спочатку
у рядку-заголовку):}
If (CurElmType<>bc_FuncVal) and (CurElmType<>bc_DestFuncToMax) and
(CurElmType<>bc_DestFuncToMin) then
CurElmType:=bc_FuncVal;
End; {Виправлений тип елемента:}
CurHeadCol[SRow].ElmType:=CurElmType;
If CurElmType=bc_Number then {записуємо число, якщо розпізналося:}
CurHeadCol[SRow].AsNumber:=CurFloatVal
Else
Begin {якщо число не розпізналося, то записуємо як назву змінної:}
With CurHeadCol[SRow] do
Begin
AsVarName:=CurGrid. Cells [Self.CHeadColNum,
SRow+bc_LTaskRowsBeforeVars+Self.CHeadRowNum]; {назва}
VarInitPos:=SRow; {номер п/п у стовпці в умові задачі}
{Ознака, що змінна спочатку була у стовпці-заголовку:}
VarInitInRow:=False;
End;
End;
End;
Function TGridFormattingProcs. ReadTableFromGrid: Boolean;
Const sc_CurProcName='ReadTableFromGrid';
{Процедура для зчитування таблиці та її заголовків із CurGrid.
Для екранної таблиці використовуються координати рядка-заголовка та
стовпця заголовка (верхнього лівого кута таблиці з заголовками):
HeadColNumInGrid (CHeadColNum) і HeadRowNumInGrid (CHeadRowNum).}
Var CurRow, CurCol, CurWidth, CurHeight: Integer;
CurFloatVal:TWorkFloat;
Begin
If Self. CurGrid=Nil then
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+
': '+sc_NoGrowingStringGrid);
ReadTableFromGrid:=False;
Exit;
End;
{Ширина і висота таблиці з заголовками:}
CurWidth:=Self. CurGrid. ColCount-Self.CHeadColNum-bc_LTaskColsBeforeVars;
CurHeight:=Self. CurGrid. RowCount-Self.CHeadRowNum-bc_LTaskRowsBeforeVars;
If (CurHeight<=0) or (CurWidth<=0) then
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+
': починаючи з комірки ['+IntToStr (Self.CHeadColNum+1)+'; '+
IntToStr (Self.CHeadRowNum+1)+'] таблиці не знайдено' + sc_TriSpot);
ReadTableFromGrid:=False;
Exit;
End;
{Виділяємо пам'ять:}
SetLength (Self. CurHeadRow, CurWidth); {рядок-заголовок}
SetLength (Self. CurHeadCol, CurHeight); {стовпець-заголовок}
SetLength (Self. CurTable, CurHeight, CurWidth); {таблиця}
{Читаємо рядок-заголовок:}
For CurCol:=0 to CurWidth-1 do ReadHeadRowCell(CurCol);
{Читаємо стовпець-заголовок:}
For CurRow:=0 to CurHeight-1 do ReadHeadColCell(CurRow);
{Читаємо таблицю коефіцієнтів:}
For CurRow:=Self.CHeadRowNum+bc_LTaskRowsBeforeVars to
Self. CurGrid. RowCount-1 do
Begin
For CurCol:=Self.CHeadColNum+bc_LTaskColsBeforeVars to
Self. CurGrid. ColCount-1 do
Begin
Try {Пробуємо інтерпретувати рядок із комірки як число:}
CurFloatVal:=StrToFloat (CurGrid. Cells [CurCol, CurRow]);
Except{Якщо не вдалося, то вважаємо це число нулем:}
CurFloatVal:=0;
End;
Self. CurTable [CurRow-bc_LTaskRowsBeforeVars-Self.CHeadRowNum,
CurCol-bc_LTaskColsBeforeVars-Self.CHeadColNum]:=CurFloatVal;
End;
End;
{Після читання зміни в екранній таблиці враховані:}
Self. CurGridModified:=False;
ReadTableFromGrid:=True;
End;
Function TGridFormattingProcs. WriteTableToGrid (SHeadColNum,
SHeadRowNum: Integer; ToTuneColWidth: Boolean=True):Boolean;
{Процедура для відображення таблиці та її заголовків у CurGrid.}
Const sc_CurProcName='WriteTableToGrid';
Var CurRow, CurCol, CurWidth, CurHeight: Integer;
CurElmType:THeadLineElmType;
Begin
If Self. CurGrid=Nil then
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+
': GrowingStringGrid не заданий!..');
WriteTableToGrid:=True;
Exit;
End;
{Ширина і висота таблиці:}
Self. GetTaskSizes (CurWidth, CurHeight);
If (CurHeight<=0) or (CurWidth<=0) then
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_EmptyTable);
WriteTableToGrid:=False;
Exit;
End;
{Виділяємо комірки для таблиці у екранному CurGrid:}
Self. CurGrid. ColCount:=CurWidth+SHeadColNum+1;
Self. CurGrid. RowCount:=CurHeight+SHeadRowNum+1;
{Відображаємо рядок-заголовок:}
For CurCol:=SHeadColNum+1 to Self. CurGrid. ColCount-1 do
Begin
CurElmType:=CurHeadRow [CurCol-1-SHeadColNum].ElmType;
If CurElmType=bc_Number then {записуємо число, якщо є числом:}
CurGrid. Cells [CurCol, SHeadRowNum]:=
FloatToStr (CurHeadRow[CurCol-1-SHeadColNum].AsNumber)
Else{Якщо це не число, то це рядок з якоюсь назвою. Записуємо:}
Self. CurGrid. Cells [CurCol, SHeadRowNum]:=
CurHeadRow [CurCol-1-SHeadColNum].AsVarName;
End;
{Відображаємо стовпець-заголовок:}
For CurRow:=SHeadRowNum+1 to Self. CurGrid. RowCount-1 do
Begin
CurElmType:=CurHeadCol [CurRow-1-SHeadRowNum].ElmType;
If CurElmType=bc_Number then {записуємо число, якщо є числом:}
CurGrid. Cells [SHeadColNum, CurRow]:=
FloatToStr (CurHeadCol[CurRow-1-SHeadRowNum].AsNumber)
Else{Якщо це не число, то це рядок з якоюсь назвою. Записуємо:}
Self. CurGrid. Cells [SHeadColNum, CurRow]:=
CurHeadCol [CurRow-1-SHeadRowNum].AsVarName;
End;
{Відображаємо таблицю коефіцієнтів:}
For CurRow:=SHeadRowNum+1 to Self. CurGrid. RowCount-1 do
Begin
For CurCol:=SHeadColNum+1 to Self. CurGrid. ColCount-1 do
CurGrid. Cells [CurCol, CurRow]:=
FloatToStr (Self. CurTable [CurRow-1-SHeadRowNum, CurCol-1-SHeadColNum]);
End;
{Комірка на перехресті заголовків пуста:}
If (SHeadRowNum<Self. CurGrid. RowCount) and
(SHeadColNum<Self. CurGrid. ColCount) then
CurGrid. Cells [SHeadColNum, SHeadRowNum]:='';
{Після запису в екранну таблицю: зміни, що могли бути у ній, вважаємо
затертими:}
Self. CurGridModified:=False;
{Якщо задано, настроюємо ширини стовпців по довжині тексту у комірках:}
If ToTuneColWidth then Self. CurGrid. TuneColWidth;
WriteTableToGrid:=True;
End;
Procedure TGridFormattingProcs. GetTaskSizes (Var DWidth, DHeight: Integer);
{Визначення розмірів таблиці задачі, і корегування довжини заголовків
таблиці та зовнішнього масиву таблиці (масиву масивів).}
Begin
DHeight:=Length (Self. CurTable);
If DHeight>0 then
DWidth:=Length (Self. CurTable[0])
Else DWidth:=0;
If DWidth=0 then DHeight:=0;
If DWidth>Length (Self. CurHeadRow) then
DWidth:=Length (Self. CurHeadRow);
If DHeight>Length (Self. CurHeadCol) then
DHeight:=Length (Self. CurHeadCol);
{Якщо комірок немає, то:}
If DWidth=0 then
Begin
{Зовнійшій масив встановлюємо у нульову довжину:}
SetLength (Self. CurTable, 0);
{Заголовки теж:}
SetLength (Self. CurHeadRow, 0);
SetLength (Self. CurHeadCol, 0);
End;
End;
{Розміри прочитаної таблиці задачі:}
Function TGridFormattingProcs. TaskWidth: Integer;
Var CurWidth, CurHeight: Integer;
Begin
Self. GetTaskSizes (CurWidth, CurHeight);
TaskWidth:=CurWidth;
End;
Function TGridFormattingProcs. TaskHeight: Integer;
Var CurWidth, CurHeight: Integer;
Begin
Self. GetTaskSizes (CurWidth, CurHeight);
TaskHeight:=CurHeight;
End;
Function TGridFormattingProcs. GetTask (ToPrepareGrid: Boolean=True):Boolean;
{Зчитування умови задачі із CurGrid та відображення прочитаного
на тому ж місці, де воно було. Працює у режимах
fs_EnteringEqs і fs_EnteringLTask.}
Const sc_CurProcName='GetTask';
Var Res1: Boolean;
Procedure DoGetTask;
Begin
If ToPrepareGrid then
CurGrid. ShrinkToFilled (Self.CHeadColNum+1, Self.CHeadRowNum+1);
{Читаємо комірки таблиці:}
Res1:=Self. ReadTableFromGrid;
{Відображаємо те, що вийшло прочитати, у тих самих комірках на екрані:}
If Not (Self. WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum)) then
Res1:=False;
End;
Begin
If Self. CurGrid=Nil then
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+': '+sc_NoGrowingStringGrid);
GetTask:=False;
Exit;
End;
Case Self. CurFormatState of
fs_EnteringEqs: {режим редагування системи лінійних рівнянь:}
Begin
{Зчитуємо таблицю. Як рядок-заголовок зчитуємо автоматично
сформовані назви змінних x1…xn та множник вільних членів (1).
Як стовпець-заголовок зчитуємо стовпець нумерації.
При переході до режиму вирішування задачі у цей стовпець
будуть скопійовані вільні члени (режим способу 1, fs_SolvingEqsM1),
або нулі (режим способу 2, fs_SolvingEqsM2):}
DoGetTask;
If Not(Res1) then Begin GetTask:=False; Exit; End;
End;
fs_EnteringLTask: {режим редагування форми задачі лінійного програмування:}
Begin
{Зчитуємо таблицю умови для задачі ЛП максимізації або
мінімізації лінійної форми (функції з умовами-нерівностями,
рівняннями та обмеженнями невід'ємності, імена змінних, нерівностей,
функцій):}
DoGetTask;
If Not(Res1) then Begin GetTask:=False; Exit; End;
End;
fs_FreeEdit: {режим вільного редагування:}
Begin
{Читаємо таблицю, рядок-заголовок, стовпець-заголовок:}
DoGetTask;
If Not(Res1) then Begin GetTask:=False; Exit; End;
End;
Else {інші режими:}
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName + sc_CantReadTaskInCurMode
+ sc_TriSpot);
GetTask:=False;
Exit;
End;
End;
{If ToPrepareGrid then CurGrid. TuneColWidth;}
Self. EqM1TaskPrepared:=False;
Self. EqM2TaskPrepared:=False;
Self.LTaskPrepared:=False;
GetTask:=True;
End;
Procedure TGridFormattingProcs. Refresh;
Const sc_CurProcName='Refresh';
Var Res1: Boolean;
Begin
If Self. CurFormatState<>fs_NoFormatting then
Begin
If Self. CurGrid=Nil then
Begin
If Self. CurOutConsole<>Nil then
Self. CurOutConsole. Lines. Add (sc_CurProcName+': '+
sc_NoGrowingStringGrid);
Exit;
End;
Res1:=False;
{Якщо таблиця редагована або ще не читана, то запускаємо її зчитування:}
If Self. CurGridModified or (Self. TaskWidth<=0) then Res1:=Self. GetTask;
If Not(Res1) then {Якщо таблиця не була віджображена у GetTask, відображаємо:}
Self. WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum);
End;
End;
Procedure TGridFormattingProcs. ResetModified; {скидає прапорець зміненого стану}
Begin
Self. CurGridModified:=False;
End;
Procedure TGridFormattingProcs. UndoChanges;
{Відкидає останні зміни (ResetModified+Refresh).}
Begin
Self. ResetModified; Self. Refresh;
End;
Procedure Transpose (Var SDMatrix:TFloatMatrix);
{Транспонування двовимірної матриці.}
Var CurCol, CurRow, CurWidth, CurHeight: Integer;
SafeElm:TWorkFloat;
Begin
CurHeight:=Length(SDMatrix);
If CurHeight>0 then CurWidth:=Length (SDMatrix[0])
Else CurWidth:=0;
If (CurHeight=0) or (CurWidth=0) then Exit;
{Збільшуємо розміри матриці до квадратних:}
IfCurWidth>CurHeightthen{Якщо ширина була більша за висоту:}
Begin
SetLength (SDMatrix, CurWidth, CurWidth); {збільшуємо висоту}
End
ElseifCurWidth<CurHeightthen{Якщо висота була більша за ширину:}
Begin
SetLength (SDMatrix, CurHeight, CurHeight); {збільшуємо ширину}
End;
{Міняємо елементи місцями: рядки будуть стовпцями, а стовпці – рядками:}
For CurRow:=0 to Length(SDMatrix) – 1 do
Begin
For CurCol:=CurRow + 1 to Length (SDMatrix[CurRow]) – 1 do
Begin
SafeElm:=SDMatrix [CurRow, CurCol];
SDMatrix [CurRow, CurCol]:=SDMatrix [CurCol, CurRow];
SDMatrix [CurCol, CurRow]:=SafeElm;
End;
End;
{Ширина тепер буде така як була висота, а висота – як була ширина:}
SetLength (SDMatrix, CurWidth, CurHeight);
End;
Function TGridFormattingProcs. MakeDualLTask: Boolean;
{Перехід від зчитаної умови задачі максимізації чи мінімізації
лінійної форми до двоїстої задачі. Працює у режимі редагування
задачі максимізації-мінімізації (fs_EnteringLTask).
За правилом двоїсту задачу потрібно мінімізувати, якщо для прямої
потрібно було знайти максимум, і максимізувати, якщо для прямої потрібно
було знайти мінімум.