IPCTGMakerImpl:
CEDAR
PROGRAM
IMPORTS OrderedSymbolTableRef, Misc, IPParams, IPCTG, IPCoTab, IPCoVerifier
EXPORTS IPCTGMaker = BEGIN OPEN IPCTGMaker;
--This piece of code was written with the assumption that channels do not have zero width.
--So all the error checkings '%Debugging%' and some internal routines uses that information.
--But this assumption is no longer valid. An easy way out is by add the 2 lines below
-- marked by: '***Added to allow chWidth = 0***'
--This is not an efficient implement, a lot of design and efficiency improvements
-- can be made to it. However it is ample for the size of problems we are
-- dealing with and since it is only called once (ie. to enter the topological domain)
-- the pay off is not great. But if it ever becomes necessary to increase the efficiency,
-- I can give you a lot of pointers on how to do it.
--CSChow: January 23, 1985 9:45:19 pm PST
Create:
PUBLIC
PROC[]
RETURNS[Ref]= {
RETURN [NEW[Rep ← [comps:, horPreChs: OrderedSymbolTableRef.CreateTable[preChCompareProc], verPreChs: OrderedSymbolTableRef.CreateTable[preChCompareProc], xMin:, yMin:, xMax:, yMax:]]]}; --Create --
Destroy:
PUBLIC
PROC [r: Ref]= {
DeletePreChs[r];
r.horPreChs.DestroyTable[];
r.verPreChs.DestroyTable[];
}; --Destroy --
ConstructCTG:
PUBLIC
PROC[r: Ref, cV: IPCoVerifier.Ref, chWidth:
NAT ← IPParams.ChDefaultWidth, yPrimary, maxChWidth:
BOOL ←
TRUE]
RETURNS[needGeom:
BOOL ←
FALSE, ctg:
IPCTG.Ref]= {
preChs: OrderedSymbolTableRef.Table;
mPreCh: PreCh ← NIL;
wSpan: Misc.Interval ← IF yPrimary THEN cV.GetBRect.x ELSE cV.GetBRect.y;
cl: Clusters ← ClCreate[];
primClCnt: NAT;
chWidth ← chWidth.
SUCC;
--***Added to allow chWidth = 0***
--The rest of the code can now proceed with chWidth > 0
--(0) Initialize the input-
AcceptCoVerifier[r, cV, chWidth];
--(1) Form primary clusters--
preChs ← IF yPrimary THEN r.horPreChs ELSE r.verPreChs;
WHILE (mPreCh ← GetNextPreCh[preChs, mPreCh]) #
NIL
DO
mWind: Misc.Window ← Misc.WindCreate[wSpan.min, wSpan.max];
mRange: Misc.Interval ← mPreCh.range;
mSpan: Misc.Interval ← mPreCh.span;
tPreCh: PreCh ← GetNextPreCh[preChs, mPreCh];
tSpan: Misc.Interval;
cluster: LIST OF PreCh ← NIL;
IF mPreCh.posComp
THEN {
IF mPreCh.cluster = 0 THEN ERROR ELSE LOOP}; --%Debugging%--
WHILE tPreCh #
NIL
DO {
IF mWind.WindCurtainsCoverIntl[mSpan] THEN EXIT;
tSpan ← tPreCh.span;
IF (NOT tPreCh.posComp) OR mSpan.IntlIntersect[tSpan] = NIL THEN GOTO nextTest;
IF mWind.WindPassesIntl[tSpan]
OR mRange.IntlContainPt[tPreCh.coord]
THEN {cluster ← CONS[tPreCh, cluster]; mRange ← mRange.IntlIntersect[tPreCh.range]}
ELSE GOTO nextTest;
IF mRange.IntlOneOf = interval THEN GOTO nextTest; --%Debugging%--
ERROR;
EXITS
nextTest => {mWind.WindAddCurtain[tSpan];
tPreCh ← GetNextPreCh[preChs, tPreCh]}}
ENDLOOP;
ClClusterize[cl, mPreCh, cluster];
ENDLOOP;
--(2) Form secondary clusters--
primClCnt ← cl.count;
FOR i:
NAT
IN [1..primClCnt]
DO
mCl: Cluster ← cl.clusters[i];
nPs: LIST OF PreCh;
pPs: LIST OF PreCh;
IF mCl = NIL THEN LOOP;
nPs ← mCl.negPreChs;
pPs ← mCl.posPreChs;
mCl.negBndCl ← ClMerge2[cl, nPs.first.negBnd, pPs.first.negBnd];
IF cl.clusters[mCl.negBndCl].range.IntlOneOf # interval THEN needGeom ← TRUE;
IF nPs.first.negBnd.posComp # pPs.first.negBnd.posComp
THEN {
negP: PreCh ← nPs.first;
posP: PreCh ← pPs.first;
IF negP.negBnd.negBnd = negP
AND posP.negBnd.negBnd = posP
THEN {
cl.clusters[mCl.negBndCl].negBndCl ← i;
GOTO ok;};
IF negP.negBnd.posBnd = negP
AND posP.negBnd.posBnd = posP
THEN {
cl.clusters[mCl.negBndCl].posBndCl ← i;
GOTO ok;};
ERROR; -- %Shouldn't Happen%--
DO
IF nPs.rest = NIL THEN EXIT;
cl.clusters[ClMerge2[cl, nPs.first.posBnd, nPs.rest.first.negBnd]].posBndCl ← i;
nPs ← nPs.rest;
ENDLOOP;
DO
IF pPs.rest = NIL THEN EXIT;
cl.clusters[ClMerge2[cl, pPs.first.posBnd, pPs.rest.first.negBnd]].negBndCl ← i;
pPs ← pPs.rest;
ENDLOOP;
mCl.posBndCl ← ClMerge2[cl, nPs.first.posBnd, pPs.first.posBnd];
IF cl.clusters[mCl.posBndCl].range.IntlOneOf # interval THEN {needGeom ← TRUE};
IF nPs.first.posBnd.posComp # pPs.first.posBnd.posComp
THEN {
negP: PreCh ← nPs.first;
posP: PreCh ← pPs.first;
IF negP.posBnd.negBnd = negP
AND posP.posBnd.negBnd = posP
THEN {
cl.clusters[mCl.posBndCl].negBndCl ← i;
GOTO ok;};
IF negP.posBnd.posBnd = negP
AND posP.posBnd.posBnd = posP
THEN {
cl.clusters[mCl.posBndCl].posBndCl ← i;
GOTO ok;};
ERROR; -- %Shouldn't Happen%--
ENDLOOP;
chWidth ← chWidth.
PRED;
***Added to allow chWidth = 0***
-- Nullifies the effect eariler
ctg ← ClToCTG[cl, chWidth, maxChWidth];
FOR indx:
NAT
IN [1..r.comps.count]
DO
InsertComp[r.comps.compItems[indx], cl]
ENDLOOP;
}; -- ConstructCTG--
--########### Private procedures ###########--
PosInfinity: INT = LAST[INT];
NegInfinity: INT = FIRST[INT];
preChCompareProc: OrderedSymbolTableRef.CompareProc ={
p1: PreCh ← NARROW[r1];
p2: PreCh ← NARROW[r2];
IF p1 = p2 THEN RETURN [equal];
IF p1.coord> p2.coord THEN RETURN [greater];
IF p1.coord < p2.coord THEN RETURN [less];
IF p1.negBnd.coord > p2.negBnd.coord THEN RETURN [greater];
IF p1.negBnd.coord < p2.negBnd.coord THEN RETURN [less];
ERROR; --%Shouldnt Happen%--
}; --preChCompareProc--
AcceptCoVerifier:
PROC[r: Ref, cV: IPCoVerifier.Ref, chWidth:
NAT]= {
OPEN rc: r.comps;
aP: IPCoVerifier.EachCompItemAction ={
quit ← FALSE;
rc.compItems[(rc.count ← rc.count + 1)] ← NEW[CompItemRep ← [cI.comp]];
AcceptCompItem[r, cI, rc.count]}; --aP--
DeletePreChs[r];
r.comps ← NEW[CompItemsRep];
AcceptBRect[r, cV.GetBRect, chWidth];
cV.CompItems[aP];
}; --AcceptCoVerifier --
DeletePreChs:
PROC[r: Ref] ={
preChList: LIST OF PreCh ← NIL;
p:
PROC[i:
REF]
RETURNS[
BOOL] ={pCh: PreCh ←
NARROW[i];
preChList ← CONS[pCh, preChList];
RETURN [FALSE]}; --p--
IF r.horPreChs.Size < r.verPreChs.Size
THEN {r.horPreChs.EnumerateIncreasing[p]}
ELSE {r.verPreChs.EnumerateIncreasing[p]};
WHILE preChList #
NIL
DO
PreChSetBnds[preChList.first, NIL, NIL];
preChList ← preChList.rest;
ENDLOOP;r.comps ← NIL;
r.horPreChs.DeleteAllItems[];
r.verPreChs.DeleteAllItems[];
}; --DeletePreChs--
AcceptBRect:
PROC[r: Ref, bRect: Misc.Rect, margin:
NAT] ={
I: PROC[min, max: INT] RETURNS[Misc.Interval] = Misc.IntlCreate;
south, east, north, west: PreCh;
r.xMin ← bRect.xMin - margin;
r.yMin ← bRect.yMin - margin;
r.xMax ← bRect.xMax + margin;
r.yMax ← bRect.yMax + margin;
south ← NewPreCh[hor, FALSE, r.yMin, I[r.xMin, r.xMax], I[r.yMin, PosInfinity], NIL];
east ← NewPreCh[ver, TRUE, r.xMax, I[r.yMin, r.yMax], I[NegInfinity, r.xMax], NIL];
north ← NewPreCh[hor, TRUE, r.yMax, I[r.xMin, r.xMax], I[NegInfinity, r.yMax], NIL];
west ← NewPreCh[ver, FALSE, r.xMin, I[r.yMin, r.yMax], I[r.xMin, PosInfinity], NIL];
PreChSetBnds[south, west, east];
PreChSetBnds[east, south, north];
PreChSetBnds[north, west, east];
PreChSetBnds[west, south, north];
InsertPreCh[r, south];
InsertPreCh[r, east];
InsertPreCh[r, north];
InsertPreCh[r, west];
}; --AcceptBRect--
AcceptCompItem:
PROC[r: Ref, cI: IPCoVerifier.CompItem, compIndex: CompItemIndices] ={
OPEN h: cI.hint;
I: PROC[min, max: INT] RETURNS[Misc.Interval] = Misc.IntlCreate;
co: IPCoTab.Component ← cI.comp;
south, east, north, west: PreCh;
swC, seC, neC, nwC: CornerPreChs ← NIL;
bR, swR0, seR0, neR0, nwR0, swR1, seR1, neR1, nwR1: Misc.Rect;
southSpan, eastSpan, northSpan, westSpan: Misc.Interval;
epsilon: NAT ← 1; --This has very subtle effects--
hC, vC: PreCh;
bR ← IPCoTab.GetBRect[co];
[swR0, seR0, neR0, nwR0] ← IPCoTab.GetCornerRects[co, 0];
[swR1, seR1, neR1, nwR1] ← IPCoTab.GetCornerRects[co, 1];
southSpan ← northSpan ← bR.x;
eastSpan ← westSpan ← bR.y;
IF h.sw
THEN {southSpan ← southSpan.IntlSubtract[swR1.x];
westSpan ← westSpan.IntlSubtract[swR1.y]};
IF h.se
THEN {southSpan ← southSpan.IntlSubtract[seR1.x];
eastSpan ← eastSpan.IntlSubtract[seR1.y]};
IF h.ne
THEN {northSpan ← northSpan.IntlSubtract[neR1.x];
eastSpan ← eastSpan.IntlSubtract[neR1.y]};
IF h.nw
THEN {northSpan ← northSpan.IntlSubtract[nwR1.x];
westSpan ← westSpan.IntlSubtract[nwR1.y]};
south ← NewPreCh[hor, TRUE, bR.yMin, southSpan, I[NegInfinity, bR.yMin], co];
east ← NewPreCh[ver,FALSE,bR.xMax, eastSpan, I[bR.xMax, PosInfinity], co];
north ← NewPreCh[hor, FALSE, bR.yMax, northSpan, I[bR.yMax, PosInfinity], co];
west ← NewPreCh[ver, TRUE, bR.xMin, westSpan, I[NegInfinity, bR.xMin], co];
IF h.sw
THEN {
hC ← NewPreCh[hor, TRUE, swR0.yMax, swR1.x, swR0.y, co];
vC ← NewPreCh[ver, TRUE, swR0.xMax, swR1.y, swR0.x,co];
PreChSetBnds[hC, west, vC];
PreChSetBnds[vC, south, hC];
swC ← NEW[CornerPreChsRep ←[hor: hC, ver: vC]];
InsertPreCh[r, hC];
InsertPreCh[r, vC];};
IF h.se
THEN {
hC ← NewPreCh[hor, TRUE, seR0.yMax, seR1.x, seR0.y, co];
vC ← NewPreCh[ver, FALSE, seR0.xMin, seR1.y, seR0.x, co];
PreChSetBnds[hC, vC, east];
PreChSetBnds[vC, south, hC];
seC ← NEW[CornerPreChsRep ←[hor: hC, ver: vC]];
InsertPreCh[r, hC];
InsertPreCh[r, vC];};
IF h.ne
THEN {
hC ← NewPreCh[hor, FALSE, neR0.yMin, neR1.x, neR0.y, co];
vC ← NewPreCh[ver, FALSE, neR0.xMin, neR1.y, neR0.x, co];
PreChSetBnds[hC, vC, east];
PreChSetBnds[vC, hC, north];
neC ← NEW[CornerPreChsRep ←[hor: hC, ver: vC]];
InsertPreCh[r, hC];
InsertPreCh[r, vC];};
IF h.nw
THEN {
hC ← NewPreCh[hor, FALSE, nwR0.yMin, nwR1.x, nwR0.y,co];
vC ← NewPreCh[ver, TRUE, nwR0.xMax, nwR1.y, nwR0.x, co];
PreChSetBnds[hC, west, vC];
PreChSetBnds[vC, hC, north];
nwC ← NEW[CornerPreChsRep ←[hor: hC, ver: vC]];
InsertPreCh[r, hC];
InsertPreCh[r, vC];};
PreChSetBnds[south, (IF h.sw THEN swC.ver ELSE west), (IF h.se THEN seC.ver ELSE east)];
PreChSetBnds[east, (IF h.se THEN seC.hor ELSE south), (IF h.ne THEN neC.hor ELSE north)];
PreChSetBnds[north, (IF h.nw THEN nwC.ver ELSE west), (IF h.ne THEN neC.ver ELSE east)];
PreChSetBnds[west, (IF h.sw THEN swC.hor ELSE south), (IF h.nw THEN nwC.hor ELSE north)];
r.comps.compItems[compIndex].prinPreChs ← [south: south, east: east, north: north, west: west];
r.comps.compItems[compIndex].cornerPreChs ← [sw: swC, se: seC, ne: neC, nw: nwC];
InsertPreCh[r, south];
InsertPreCh[r, east];
InsertPreCh[r, north];
InsertPreCh[r, west];
};--AcceptCompItem--
NewPreCh:
PROC[type:
IPCTG.ChType, posComp:
BOOL, coord:
INT, span, range: Misc.Interval, comp: IPCoTab.Component]
RETURNS [PreCh] ={
RETURN [NEW[PreChRep ← [type, posComp, coord, span, range, comp]]];
}; --NewPreCh--
InsertPreCh:
PROC[r: Ref, p: PreCh] ={
SELECT p.type
FROM
hor => {r.horPreChs.Insert[p]};
ver => {r.verPreChs.Insert[p]};
ENDCASE => ERROR; }; --InsertPreCh--
GetNextPreCh:
PROC[tab: OrderedSymbolTableRef.Table, p: PreCh]
RETURNS [PreCh] ={
IF p =
NIL
THEN RETURN [NARROW[tab.LookupSmallest]]
ELSE RETURN [NARROW[tab.LookupNextLarger[p]]]};--GetNextPreCh--
--Operations on individual PreCh and CompItem--
PreChSetBnds:
PROC[p, negBnd, posBnd: PreCh] ={
IF negBnd # NIL AND negBnd.type = p.type THEN ERROR;
IF posBnd # NIL AND posBnd.type = p.type THEN ERROR;
p.negBnd ← negBnd;
p.posBnd ← posBnd;
}; --PreChSetBnds--
InsertComp:
PROC[cI: CompItem, cl: Clusters] ={
OPEN p: cI.prinPreChs, cc: cI.cornerPreChs;
swC, seC, neC, nwC: IPCoTab.CornerChannels ← NIL;
IF cc.sw # NIL THEN swC ← NEW[IPCoTab.CornerChannelsRep ← [hor: ClGetCh[cl, cc.sw.hor], ver: ClGetCh[cl, cc.sw.ver]]];
IF cc.se # NIL THEN seC ← NEW[IPCoTab.CornerChannelsRep ← [hor: ClGetCh[cl, cc.se.hor], ver:ClGetCh[cl, cc.se.ver]]];
IF cc.ne # NIL THEN neC ← NEW[IPCoTab.CornerChannelsRep ← [hor: ClGetCh[cl, cc.ne.hor], ver:ClGetCh[cl, cc.ne.ver]]];
IF cc.nw # NIL THEN nwC ← NEW[IPCoTab.CornerChannelsRep ← [hor: ClGetCh[cl, cc.nw.hor], ver:ClGetCh[cl, cc.nw.ver]]];
IPCoTab.InsertComponent[cI.co, ClGetCh[cl, p.south], ClGetCh[cl, p.east], ClGetCh[cl, p.north], ClGetCh[cl, p.west], swC, seC, neC, nwC]
}; --InsertComp--
-- ########## Cluster abstraction ########## --
Clusters: TYPE = REF ClustersRep;
ClustersRep: TYPE = RECORD[count: NAT ← 0, clusters: ARRAY ClusterIndices OF Cluster ← ALL[NIL]];
Cluster: TYPE = REF ClusterRep;
ClusterRep: TYPE = RECORD[type: IPCTG.ChType, range: Misc.Interval, negPreChs, posPreChs: LIST OF PreCh ← NIL, negBndCl, posBndCl: NAT ← 0, ch: IPCTG.Channel ← NIL, primOrdering: INT];
ClusterIndices: TYPE = [1..MaxClusterCnt];
ClCreate: PROC RETURNS [Clusters] ={RETURN [NEW[ClustersRep]]}; --ClCreate--
ClNewCluster:
PROC[cl: Clusters, type:
IPCTG.ChType, range: Misc.Interval, order:
INT ←
FIRST[
INT]]
RETURNS [ClusterIndices] ={
cl.clusters[(cl.count ← cl.count + 1)] ← NEW[ClusterRep ←[type: type, range: range, primOrdering: order]];
RETURN [cl.count]}; --ClNewCluster--
ClClusterize:
PROC[cl: Clusters, pCh: PreCh, lp:
LIST
OF PreCh] ={
cIndex: NAT ← 0;
FOR l:
LIST
OF PreCh ← lp, l.rest
UNTIL l =
NIL
DO
cIndex ← MAX[cIndex, l.first.cluster];
ENDLOOP;
IF cIndex = 0
OR cl.clusters[cIndex].primOrdering < pCh.range.min
THEN {cIndex ← ClNewCluster[cl, pCh.type, pCh.range, pCh.range.min]};
ClAddPreCh[cl, cIndex, pCh];
FOR l:
LIST
OF PreCh ← lp, l.rest
UNTIL l =
NIL
DO
IF l.first.cluster = cIndex THEN LOOP;
IF l.first.cluster = 0
THEN {ClAddPreCh[cl, cIndex, l.first]}
ELSE {ClMergeClusterInto[cl, l.first.cluster, cIndex]};
ENDLOOP;
IF cl.clusters[cIndex].range.IntlOneOf # interval THEN ERROR; -- %Debugging%--
}; --ClClusterize--
ClMerge2:
PROC[cl: Clusters, p1, p2: PreCh]
RETURNS [ClusterIndices] ={
nCl: NAT;
IF p1.type # p2.type THEN ERROR;
IF p1.cluster # 0
AND p2.cluster # 0
THEN {
IF p1.cluster = p2.cluster THEN RETURN[p1.cluster] ELSE ERROR}; -- %Shouldnt Happen%--
nCl ← MAX[p1.cluster, p2.cluster];
IF nCl = 0 THEN nCl ← ClNewCluster[cl, p1.type, p1.range];
ClAddPreCh[cl, nCl, p1];
ClAddPreCh[cl, nCl, p2];
RETURN [nCl]
};--ClMerge2--
ClMergeClusterInto:
PROC[cl: Clusters, from, into: ClusterIndices] ={
fCl: Cluster ← cl.clusters[from];
FOR l:
LIST
OF PreCh ← fCl.negPreChs, l.rest
UNTIL l =
NIL
DO
ClAddPreCh[cl, into, l.first];
ENDLOOP;
FOR l:
LIST
OF PreCh ← fCl.posPreChs, l.rest
UNTIL l =
NIL
DO
ClAddPreCh[cl, into, l.first];
ENDLOOP;
cl.clusters[from] ← NIL;
};--ClMergeClusterInto--
ClAddPreCh:
PROC[cl: Clusters, i: ClusterIndices, pCh: PreCh] ={
chList: LIST OF PreCh;
pLess:
PROC[p1, p2: PreCh]
RETURNS [
BOOL] = {
RETURN [p1.negBnd.coord < p2.negBnd.coord]
};--pLess--
IF cl.clusters[i].type # pCh.type THEN ERROR;
IF pCh.cluster = i THEN RETURN;
pCh.cluster ← i;
cl.clusters[i].range← cl.clusters[i].range.IntlIntersect[pCh.range];
IF pCh.posComp
THEN {IF (chList ← cl.clusters[i].posPreChs) = NIL OR pLess[pCh, chList.first] THEN {cl.clusters[i].posPreChs ← CONS[pCh, chList]; RETURN}}
ELSE {IF (chList ← cl.clusters[i].negPreChs) = NIL OR pLess[pCh, chList.first] THEN {cl.clusters[i].negPreChs ← CONS[pCh, chList]; RETURN}};
FOR l:
LIST
OF PreCh ← chList, l.rest
DO
IF l.rest = NIL THEN {l.rest ← LIST[pCh]; EXIT};
IF pLess[pCh, l.rest.first] THEN {l.rest ← CONS[pCh, l.rest]; EXIT}
ENDLOOP;
};--ClAddPreCh--
ClGetCh:
PROC[cl: Clusters, p: PreCh]
RETURNS [
IPCTG.Channel] ={
RETURN [cl.clusters[p.cluster].ch]}; --ClGetCh--
ClToCTG:
PROC[cl: Clusters, chWidth:
NAT, maxChWidth:
BOOL]
RETURNS [
IPCTG.Ref] ={
ctg: IPCTG.Ref ← IPCTG.Create[];
makeCh:
PROC[c: Cluster] ={
r: Misc.Interval ← c.range;
width: NAT ← IF maxChWidth THEN MAX[r.IntlLength, chWidth] ELSE chWidth;
coord:
INT ←
IF r =
NIL
THEN (c.negPreChs.first.coord + c.posPreChs.first.coord)/2
ELSE (r.min + r.max)/2;
c.ch ← ctg.CreateChannel[c.type, width, coord];
}; --makeCh--
makeChBoundary:
PROC[index: ClusterIndices] ={
c: Cluster ← cl.clusters[index];
eP:
PROC [end: {neg, pos}]
RETURNS [
IPCTG.Intersection] ={
ch: IPCTG.Channel;
iType: IPCTG.IntersectionType;
ch ←
SELECT end
FROM
neg => cl.clusters[c.negBndCl].ch,
pos => cl.clusters[c.posBndCl].ch,
ENDCASE => ERROR;
SELECT end
FROM
neg => {
SELECT index
FROM
cl.clusters[c.negBndCl].posBndCl => iType ← -1;
cl.clusters[c.negBndCl].negBndCl => iType ← 1;
ENDCASE => iType ← 0;};
pos => {
SELECT index
FROM
cl.clusters[c.posBndCl].posBndCl => iType ← -1;
cl.clusters[c.posBndCl].negBndCl => iType ← 1;
ENDCASE => iType ← 0;};
ENDCASE => ERROR;
RETURN [IPCTG.NewIn[ch: ch, type: iType]]
}; --eP--
sP:
PROC [side: {neg, pos}]
RETURNS [
LIST
OF
IPCTG.Intersection] ={
iListHd, iListTl: LIST OF IPCTG.Intersection;
iType: IPCTG.IntersectionType ← (SELECT side FROM neg => -1, pos => 1, ENDCASE => ERROR);
iListHd ← iListTl ← CONS[NIL, NIL];
FOR pChs:
LIST
OF PreCh ← (
SELECT side
FROM neg => c.negPreChs, pos => c.posPreChs,
ENDCASE =>
ERROR), pChs.rest
UNTIL pChs.rest =
NIL
DO
ch: IPCTG.Channel ← cl.clusters[pChs.first.posBnd.cluster].ch;
IF pChs.first.posBnd.cluster # pChs.rest.first.negBnd.cluster THEN ERROR; --%Debugging%--
iListTl.rest ← LIST[IPCTG.NewIn[ch: ch, type: iType]];
iListTl ← iListTl.rest
ENDLOOP;
RETURN [iListHd.rest]}; --sP--
IPCTG.SetBoundary[c.ch, eP[neg], eP[pos], sP[neg], sP[pos]]
}; --makeChBoundary--
FOR i:
NAT
IN [1..cl.count]
DO
IF cl.clusters[i] # NIL THEN makeCh[cl.clusters[i]];
ENDLOOP;
FOR i:
NAT
IN [1..cl.count]
DO
IF cl.clusters[i] # NIL THEN makeChBoundary[i];
ENDLOOP;
RETURN [ctg];
}; --ClToCTG--
END.