PALADIN / PROGRAM
.DOC
Приложение.
Текст основных процедур, реализующих алгоритм.
// file topology.h
// Cодержит определения основных классов
#include <graphics.h>
#include <stdio.h>
#include <iostream.h>
#include <fstream.h>
//
// topology.h
//
typedef unsigned int IntType;
enum TypeOfRibbon {Vertical, Gorizontical};
enum bool {false, true};
//
extern IntType SizeXLambda, SizeYLambda, WidthRibbon;
extern TypeOfRibbon RibbonType;
extern IntType XView, YView;
extern IntType MaxXLambda, MaxYLambda;
// Forward declaration for ArrayOfRibbons
class Topology;
//
class Ribbon {
public:
bool Corrected;
IntType X, Y, Len; // Start position of ribbon and length
friend ofstream& operator<<(ofstream& ofs, Ribbon& ribb);
friend ifstream& operator>>(ifstream& ifs, Ribbon& ribb);
void WriteToFile(FILE* fp);
void LoadFromFile(FILE* fp);
void ShowRibbon();
};
//
class ArrayOfRibbons {
//
friend class Topology;
class FragmentOfArray {
public:
FragmentOfArray* Next; // Point to next fragment of array
Ribbon* *Array; // Point to array of ribbons
};
protected:
IntType MaxF; // Size of first fragment of array
IntType MaxO; // Size of others fragments
IntType Total; // Current number of elements
FragmentOfArray* FirstFragment; // Point to first fragment
FragmentOfArray* CurrentFragment; // Point to current fragment
//
public:
IntType CurrentIndex; // Current index inside fragment
TypeOfRibbon RibbonsType;
ArrayOfRibbons() :
MaxF(500), MaxO(10), Total(0), CurrentIndex(0),
CurrentFragment(0), FirstFragment(0) {}
ArrayOfRibbons(IntType mF, IntType mO) :
MaxF(mF), MaxO(mO), Total(0), CurrentIndex(0),
CurrentFragment(0), FirstFragment(0) {}
~ArrayOfRibbons();
void EraseAll();
IntType NumberOfRibbons() { return Total; }
void Add(Ribbon* ribb);
Ribbon& operator[](IntType Index);
//
void ShowArray();
friend ostream& operator<<(ostream& os, ArrayOfRibbons& array);
};
//
//
class Topology {
protected:
IntType StepX, StepY;
IntType SpaceAtBottom;
IntType CurrentPage;
bool Passed;
long XScan, YScan;
void SortVert(); // Sort array of vertical ribbons
void SortGoriz(); // Sort array of gorizontal ribbons
public:
ArrayOfRibbons VertRibbons, GorizRibbons;
IntType MaxX, MaxY; //
IntType MinX, MinY; // Minimum distance bitween ribbons
Topology()
{
VertRibbons.RibbonsType = Vertical;
GorizRibbons.RibbonsType = Gorizontical;
MaxX = MaxY = 0;
MinX = MinY = 3;
CurrentPage = 0;
StepX = MinX;
StepY = MinY;
SpaceAtBottom = 16;
}
void AddVertRibbon(Ribbon* ribb);
void AddGorizRibbon(Ribbon* ribb);
bool IsEmpty(long XR, long YR, long XL, long YL);
bool IsPlaced(long XR, long YR, long XL, long YL);
void FillVert();
void FillGoriz();
void Correct();
bool ChangeScanGoriz();
bool ChangeScanVert();
void Optimize();
//
void ShowTopology();
void ChangeView(int dx, int dy);
void ChangeStep(int stepx, int stepy);
void Left();
void Right();
void Up();
void Down();
void ShowGrid();
//
friend ostream& operator<<(ostream& os, Topology& top);
};
// Текст основных процедур
TypeOfRibbon RibbonType = Vertical;
IntType SizeXLambda = 1, SizeYLambda = 1, WidthRibbon = 3;
IntType XView = 0, YView = 0;
IntType MaxXLambda, MaxYLambda;
//
// ----------------------------------------------------------------------
// Define class Topology
//-----------------------------------------------------------------------
//
void Topology::SortGoriz()
{
IntType Last = GorizRibbons.Total - 1;
if ( (GorizRibbons[Last].X + GorizRibbons[Last].Len - 1) > MaxX)
MaxX = GorizRibbons[Last].X + GorizRibbons[Last].Len - 1;
if (GorizRibbons[Last].Y + WidthRibbon > MaxY)
MaxY = GorizRibbons[Last].Y + WidthRibbon;
for(int i=0; i< Last; i++)
if(GorizRibbons[Last].Y <= GorizRibbons[i].Y) {
Ribbon ribb = GorizRibbons[Last];
for(int j=Last; j>i; j--)
GorizRibbons[j] = GorizRibbons[j-1];
GorizRibbons[i] = ribb;
break;
}
}
//
void Topology::SortVert()
{
IntType Last = VertRibbons.Total - 1;
if ( (VertRibbons[Last].Y + VertRibbons[Last].Len - 1) > MaxY)
MaxY = VertRibbons[Last].Y + VertRibbons[Last].Len - 1;
if (VertRibbons[Last].X + WidthRibbon > MaxX)
MaxX = VertRibbons[Last].X + WidthRibbon;
for(int i=0; i< Last; i++)
if(VertRibbons[Last].X <= VertRibbons[i].X) {
Ribbon ribb = VertRibbons[Last];
for(int j=Last; j>i; j--)
VertRibbons[j] = VertRibbons[j-1];
VertRibbons[i] = ribb;
break;
}
}
//
void Topology::AddGorizRibbon(Ribbon* ribb)
{
GorizRibbons.Add(ribb);
SortGoriz();
}
//
void Topology::AddVertRibbon(Ribbon* ribb)
{
VertRibbons.Add(ribb);
SortVert();
}
// Return 'false' if region contains anything ribbon
// (XL, YL) - left top point
// (XR, YR) - rigth bottom point
bool Topology::IsEmpty(long XL, long YL, long XR, long YR)
{
bool empty = true;
IntType Index = 0;
if (XL < 0 || XR > MaxX || YL < 0 || YR > MaxY)
return false;
// Scanning gorizontal ribbons
while(GorizRibbons[Index].Y+WidthRibbon-1 < YL) Index++;
while( (GorizRibbons[Index].Y <= YR) && empty) {
if (GorizRibbons[Index].X <= XR)
if ( (GorizRibbons[Index].X+GorizRibbons[Index].Len-1) >= XL)
empty = false;
Index++;
}
// Scanning vertical ribbons
Index = 0;
if (empty) {
while(VertRibbons[Index].X+WidthRibbon-1 < XL) Index++;
while( (VertRibbons[Index].X <= XR) && empty) {
if (VertRibbons[Index].Y <= YR)
if ( (VertRibbons[Index].Y+VertRibbons[Index].Len-1) >= YL)
empty = false;
Index++;
}
}
return empty;
}
// Return 'false' if region contains anything ribbon
// (XL, YL) - left top point
// (XR, YR) - rigth bottom point
bool Topology::IsPlaced(long XL, long YL, long XR, long YR)
{
bool empty = true;
IntType Index = 0;
if (XL+MinX < 0)
XL = MinX;
if (XR+MinX > MaxX)
XR = MaxX-MinX;
if (YL-MinY < 0)
YL = MinY;
if (YR+MinY > MaxY)
YR = MaxY-MinY;
// Scanning gorizontal ribbons
while(GorizRibbons[Index].Y+WidthRibbon-1 < YL-MinY) Index++;
while( (GorizRibbons[Index].Y <= YR+MinY) && empty) {
if (GorizRibbons[Index].X <= XR+MinX)
if ( (GorizRibbons[Index].X+GorizRibbons[Index].Len-1) >= XL-MinX)
empty = false;
Index++;
}
// Scanning vertical ribbons
Index = 0;
if (empty) {
while(VertRibbons[Index].X+WidthRibbon-1 < XL-MinX) Index++;
while( (VertRibbons[Index].X <= XR+MinX) && empty) {
if (VertRibbons[Index].Y <= YR+MinY)
if ( (VertRibbons[Index].Y+VertRibbons[Index].Len-1) >= YL-MinY)
empty = false;
Index++;
}
}
return empty;
}
// ---------------------------------------------
// functions Correct(), FillVert(), FillGoriz(),
// ChangeScanGoriz(), ChangeScanVert()
// for correction of topology
// ---------------------------------------------
// select type of filling ribbons
void Topology::Correct()
{
Passed = false;
if (VertRibbons.Total < GorizRibbons.Total)
FillGoriz();
else
FillVert();
}
// fill topology by gorizontical ribbons
void Topology::FillGoriz()
{
bool completed = false;
XScan = YScan = 0;
// step2: seaching empty area
while(!completed) {
while(!IsPlaced(XScan, YScan, XScan, YScan+WidthRibbon-1)
&& !completed)
completed = ChangeScanGoriz();
// step3: select rectangle area
// define width of rectangle area
if (!completed) {
long XB = XScan, YB = YScan, Width = 0, Height = 0;
while (IsPlaced(XB, YScan,
XB, YScan+WidthRibbon-1)) {
Width++;
if (XB == MaxX)
break;
else
XB++;
}
// define Height of rectangle area
if (Width > WidthRibbon) {
while (
IsEmpty( (XScan-MinX) < 0 ? 0:(XScan-MinX), YB,
(XScan+MinX+Width-1) > MaxX ? MaxX:(XScan+MinX+Width-1),
(YB+MinY) > MaxY ? MaxY:(YB+MinY)) &&
!IsEmpty( XScan-MinX-1, YB,
(XScan+MinX+Width-1) > MaxX ? MaxX:(XScan+MinX+Width-1),
YB) &&
!IsEmpty( (XScan-MinX) < 0 ? 0:(XScan-MinX),
YB, XScan+MinX+Width, YB)
)
{
Height++;
if (YB == MaxY)
break;
else
YB++;
}
// step 4: compute number of ribbons in area
IntType THeight = Height+2*MinY;
IntType numRibbons =
(Height+MinY)/(WidthRibbon+MinY);
// step 5: compute spacing bitween ribbons
float Spacing = (THeight-numRibbons*WidthRibbon)/
(numRibbons+1);
for(int i=0; i< numRibbons; i++)
{
Ribbon* ribb = new Ribbon;
ribb->X = XScan;
ribb->Y = (YScan-MinY) +
floor((i+1)*Spacing+i*WidthRibbon);
ribb->Len = Width;
ribb->Corrected = true;
AddGorizRibbon(ribb);
// ShowTopology();
}
}
// continue process
XScan = XB;
completed = ChangeScanGoriz();
}
}
// step 6: Additional correction
if (Passed == true)
return;
else {
Passed = true;
FillVert();
}
}
// Fill topology by vertical ribbons
void Topology::FillVert()
{
bool completed = false;
XScan = YScan = 0;
while(!completed) {
while(!IsPlaced(XScan, YScan, XScan+WidthRibbon-1, YScan)
&& !completed)
completed = ChangeScanVert();
// end of while
if (!completed) {
long XB = XScan, YB = YScan, Width = 0, Height = 0;
while (IsPlaced(XScan, YB,
XScan+WidthRibbon-1, YB)) {
Height++;
if (YB == MaxY)
break;
else
YB++;
}
//
if (Height > WidthRibbon) {
while (
IsEmpty( XB, (YScan-MinY) < 0 ? 0:(YScan-MinY),
(XB+MinX) > MaxX ? MaxX:(XB+MinX),
(YScan+MinY+Height-1) > MaxY ? MaxY:(YScan+MinY+Height-1)) &&
!IsEmpty( XB, YScan-MinY-1, XB,
(YScan+MinY+Height-1) > MaxY ? MaxY:(YScan+MinY+Height-1)) &&
!IsEmpty( XB, (YScan-MinY) < 0 ? 0:(YScan-MinY),
XB, YScan+MinY+Height)
)
{
Width++;
if (XB == MaxX)
break;
else
XB++;
}
// end of while
// step 4: compute number of ribbons in area
IntType TWidth = Width+2*MinY;
IntType numRibbons =
(Width+MinY)/(WidthRibbon+MinX);
// step 5: compute spacing bitween ribbons
float Spacing = (TWidth-numRibbons*WidthRibbon)/
(numRibbons+1);
for(int i=0; i< numRibbons; i++)
{
Ribbon* ribb = new Ribbon;
ribb->X = (XScan-MinX) +
floor((i+1)*Spacing+i*WidthRibbon);
ribb->Y = YScan;
ribb->Len = Height;
ribb->Corrected = true;
AddVertRibbon(ribb);
// ShowTopology();
}
}
YScan = YB;
completed = ChangeScanVert();
}
}
if (Passed == true)
return;
else {
Passed = true;
FillGoriz();
}
}
//
bool Topology::ChangeScanGoriz()
{
if (XScan == MaxX) {
XScan = 0;
if (YScan == MaxY)
return true;
else
YScan++;
}
else
XScan++;
return false;
}
//
bool Topology::ChangeScanVert()
{
if (YScan == MaxY) {
YScan = 0;
if (XScan == MaxX)
return true;
else
XScan++;
}
else
YScan++;
return false;
}