<<-- File: IPCTGMakerImpl.mesa>> <<-- Last Edited by: CSChow, January 23, 1985 9:53:38 pm PST>> <<>> <<--Documentation will come later after consolidating the design -->> DIRECTORY OrderedSymbolTableRef, IPParams, Misc, IPCoTab, IPCTG, IPCoVerifier, IPCTGMaker; 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%-- EXITS ok => NULL;}; 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%-- EXITS ok => NULL;}; 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.