-- File: IPEditPrimitivesImpl.mesa
-- Last Edited by: CSChow, February 1, 1985 11:23:52 am PST
--Intro: Welcome to the 'underground world'. It has been quite thoroughly debugged. Try not to
-- change anything here, if possible, as they are sensitive.
DIRECTORY
IPCoTab,
IPCB,
IPCTG,
IPBasicOps,
IPEditOps,
IPEditPrimitives;
IPEditPrimitivesImpl: CEDAR PROGRAM
IMPORTS IPCB, IPBasicOps, IPCTG, IPCoTab, IPEditOps
EXPORTS IPEditPrimitives = BEGIN OPEN BO: IPBasicOps, EO: IPEditOps, CB: IPCB, CTG: IPCTG, CoTab: IPCoTab, IPEditPrimitives;
InvalidArgs: PUBLIC ERROR[editPrim: ATOM] = CODE;
BreakCross: PUBLIC PROC [refCh, chToBreak, newCh1: CTG.Channel]={
negBrPt: CB.IntersectionNode ← CB.GetINode[chToBreak.boundary, refCh, neg];
posBrPt: CB.IntersectionNode ← CB.GetINode[chToBreak.boundary, refCh, pos];
IF BreakCrossChk[refCh, chToBreak] THEN NULL ELSE ERROR InvalidArgs[$BreakCross];
BreakCross Failure: Invalid inputs--
CB.INodeDual[negBrPt].intersection.type ← CB.TNeg;
CB.INodeDual[posBrPt].intersection.type ← CB.TPos;
CB.Fragment[chToBreak.boundary, negBrPt.negComp, posBrPt.negComp, chToBreak, newCh1];
[] ← CB.SetEnd[chToBreak.boundary, CB.SideRemovel[newCh1.boundary, neg], pos];
[] ← CB.SetEnd[newCh1.boundary, CB.SideRemovel[newCh1.boundary, pos], neg];
EO.CBSwapChsInComps[newCh1.boundary, chToBreak, newCh1]
}; --BreakCross--
BreakCrossChk: PUBLIC PROC[refCh, chToBreak: CTG.Channel] RETURNS [BOOL] ={
rNd: CB.IntersectionNode ← CB.GetINode[refCh.boundary, chToBreak, neg];
cNd: CB.IntersectionNode ← CB.GetINode[chToBreak.boundary, refCh, neg];
IF rNd = NIL OR rNd.intersection.type # CB.Cross OR cNd = NIL OR cNd.intersection.type # CB.Cross THEN RETURN[FALSE] ELSE RETURN[TRUE];
}; --BreakCrossChk--
FormCross: PUBLIC PROC [refCh, negCh, posCh: CTG.Channel]={
nChEnd: CB.IntersectionNode ← CB.GetEnd[negCh.boundary, pos];
pChEnd: CB.IntersectionNode ← CB.GetEnd[posCh.boundary, neg];
IF FormCrossChk[refCh, negCh, posCh] THEN NULL ELSE ERROR InvalidArgs[$FormCross]; --FormCross Failure: Invalid inputs--
EO.CBSwapChsInComps[posCh.boundary, posCh, negCh];
CB.INodeDual[nChEnd].intersection.type ← CB.Cross;
CB.INodeDual[pChEnd].intersection.type ← CB.Cross;
CB.SetINodeComps[nChEnd, CB.NthComponent[negCh.boundary, neg, -1], CB.NthComponent[posCh.boundary, neg, 1]];
CB.SetINodeComps[pChEnd, CB.NthComponent[negCh.boundary, pos, -1], CB.NthComponent[posCh.boundary, pos, 1]];
[] ← CB.SideAddh[negCh.boundary, nChEnd, neg];
[] ← CB.SideAddh[negCh.boundary, pChEnd, pos];
CB.Merge[negCh.boundary, posCh.boundary, negCh];
}; --FormCross--
FormCrossChk: PUBLIC PROC[refCh, negCh, posCh: CTG.Channel] RETURNS [BOOL] ={
IF CB.EndCh[refCh.boundary, negCh] OR CB.EndCh[refCh.boundary, posCh] THEN RETURN [FALSE];
IF CB.XingCount[refCh.boundary, negCh, neg] # CB.XingCount[refCh.boundary, posCh, pos]
OR CB.XingCount[refCh.boundary, negCh, neg] < 0 THEN RETURN[FALSE] ELSE RETURN [TRUE];
}; --FormCrossChk--
FormZ: PUBLIC PROC[refCh: CTG.Channel, negComp, posComp: CoTab.Component, zType: CB.Side, newCh1, newCh2: CTG.Channel] ={
spineCB: CB.Ref ← newCh2.boundary;
IF FormZChk[refCh, negComp, posComp, zType] THEN NULL ELSE ERROR InvalidArgs[$FormZ];
CB.Fragment[refCh.boundary, negComp, posComp, refCh, newCh1];
EO.CBSwapChsInComps[newCh1.boundary, refCh, newCh1, 1];
SELECT zType FROM
neg => {
SELECT refCh.type FROM
hor => {EO.MakeLCorner[newCh2, refCh, nw];
EO.MakeLCorner[newCh2, newCh1, se];};
ver => {EO.MakeLCorner[newCh2, refCh, sw];
EO.MakeLCorner[newCh2, newCh1, ne];};
ENDCASE => ERROR;};
pos => {
SELECT refCh.type FROM
hor => {EO.MakeLCorner[newCh2, refCh, sw];
EO.MakeLCorner[newCh2, newCh1, ne];};
ver => {EO.MakeLCorner[newCh2, refCh, se];
EO.MakeLCorner[newCh2, newCh1, nw];};
ENDCASE => ERROR;};
ENDCASE => ERROR;
IF (zType = neg AND refCh.type = hor) OR (zType = pos AND refCh.type = ver) THEN {
CB.SideSetComp[spineCB, posComp, neg];
CB.SideSetComp[spineCB, negComp, pos];
EO.CoSetCornerChs[negComp, newCh2, refCh];
EO.CoSetCornerChs[posComp, newCh2, newCh1];
EO.CoSwapChs[negComp, refCh, newCh1];
};
IF (zType = neg AND refCh.type = ver) OR (zType = pos AND refCh.type = hor) THEN {
CB.SideSetComp[spineCB, negComp, neg];
CB.SideSetComp[spineCB, posComp, pos];
EO.CoSetCornerChs[negComp, newCh2, newCh1];
EO.CoSetCornerChs[posComp, newCh2, refCh];
EO.CoSwapChs[posComp, refCh, newCh1];
};
}; --FormZ--
FormZChk: PUBLIC PROC[refCh: CTG.Channel, negComp, posComp: CoTab.Component, zType: CB.Side] RETURNS [BOOL] ={
OPEN nPC: negComp.prinChannels, nCS: negComp.shape.cornerSpaces, nCC: negComp.cornerChannels, pPC: posComp.prinChannels, pCS: posComp.shape.cornerSpaces, pCC: posComp.cornerChannels;
IF ~ CTG.ComponentOn[refCh, negComp, neg] AND ~ CTG.ComponentOn[refCh, posComp, pos] THEN RETURN[FALSE];
IF EO.CoXingCount[negComp, refCh] # EO.CoXingCount[posComp, refCh] THEN RETURN [FALSE];
SELECT refCh.type FROM
hor => {SELECT zType FROM
neg => {IF nCC.nw # NIL OR pCC.se # NIL OR nCS.nw = NIL OR pCS.se = NIL THEN RETURN[FALSE];};
pos => {IF nCC.ne # NIL OR pCC.sw # NIL OR nCS.ne = NIL OR pCS.sw = NIL THEN RETURN[FALSE];};
ENDCASE => ERROR;};
ver => {SELECT zType FROM
neg => {IF nCC.ne # NIL OR pCC.sw # NIL OR nCS.ne = NIL OR pCS.sw = NIL THEN RETURN[FALSE];};
pos => {IF nCC.se # NIL OR pCC.nw # NIL OR nCS.se = NIL OR pCS.nw = NIL THEN RETURN[FALSE];};
ENDCASE => ERROR;};
ENDCASE => ERROR;
RETURN [TRUE]
}; --FormZChk--
RemoveZ: PUBLIC PROC[zSpine: CTG.Channel] RETURNS [negCh, posCh: CTG.Channel, negComp, posComp: CoTab.Component, zType: CB.Side] --negCh ~ refCh; posCh ~ newCh1-- ={
nNd: CB.IntersectionNode ← CB.GetEnd[zSpine.boundary, neg];
pNd: CB.IntersectionNode ← CB.GetEnd[zSpine.boundary, pos];
IF RemoveZChk[zSpine] THEN NULL ELSE ERROR InvalidArgs[$RemoveZ];
SELECT nNd.intersection.type FROM
CB.LNeg => {negCh ← nNd.intersection.ch; posCh ← pNd.intersection.ch;
negComp ← zSpine.boundary.posComp; posComp ← zSpine.boundary.negComp;
zType ← IF zSpine.type = hor THEN pos ELSE neg};
CB.LPos => {negCh ← pNd.intersection.ch; posCh ← nNd.intersection.ch;
negComp ← zSpine.boundary.negComp; posComp ← zSpine.boundary.posComp;
zType ← IF zSpine.type = hor THEN neg ELSE pos};
ENDCASE => ERROR;
EO.CoClearCornerChs[zSpine.boundary.negComp, zSpine, posCh];
EO.CoClearCornerChs[zSpine.boundary.posComp, zSpine, negCh];
EO.CBSwapChsInComps[posCh.boundary, posCh, negCh];
CB.DestroyINode[nNd];
CB.DestroyINode[pNd];
CB.Merge[negCh.boundary, posCh.boundary, negCh];
}; --RemoveZ--
RemoveZChk: PUBLIC PROC[zSpine: CTG.Channel] RETURNS [BOOL] ={
zCB: CB.Ref ← zSpine.boundary;
IF zCB.negComp # NIL AND zCB.posComp # NIL AND (CB.GetEnd[zCB, neg].intersection.type * CB.GetEnd[zCB, pos].intersection.type = -1) THEN RETURN[TRUE] ELSE RETURN [FALSE];
}; --RemoveZChk--
TtoL: PUBLIC PROC [refCh: CTG.Channel, whichEnd, lType: CB.Side, endCo: CoTab.Component, newCh1: CTG.Channel]={
rCB: CB.Ref ← refCh.boundary;
bndNd: CB.IntersectionNode ← CB.GetEnd[rCB, whichEnd];
bndCh: CTG.Channel ← bndNd.intersection.ch;
newNd: CB.IntersectionNode;
IF TtoLChk [refCh, whichEnd, lType, endCo] THEN NULL ELSE ERROR InvalidArgs[$TtoL];
CB.Fragment[bndCh.boundary, endCo, CB.INodeDual[bndNd].posComp, bndCh, newCh1];
SELECT lType FROM
neg => {
bndNd.intersection.type ← CB.LNeg;
EO.CBSwapChsInComps[newCh1.boundary, bndCh, newCh1];
SELECT whichEnd FROM
neg => {[] ← CB.SideRemoveh[bndCh.boundary, pos];
newNd ← CB.SideAddl[rCB, CB.ItoINode[CTG.NewIn[newCh1, CB.TPos], refCh], pos];
CB.SetINodeComps[newNd, endCo, CB.INodeDual[bndNd].posComp];};
pos => {[] ← CB.SideRemoveh[bndCh.boundary, neg];
newNd ← CB.SideAddh[rCB, CB.ItoINode[CTG.NewIn[newCh1, CB.TPos], refCh], pos];
CB.SetINodeComps[newNd, CB.INodeDual[bndNd].posComp, endCo];};
ENDCASE => ERROR;
[] ← CB.SetEnd[bndCh.boundary, CB.INodeDual[bndNd], pos];
[] ← CB.SetEnd[newCh1.boundary, CB.ItoINode[CTG.NewIn[refCh, CB.TEnd], newCh1], neg];
EO.CoSetCornerChs[endCo, refCh, bndCh];
CB.SetUpDuals[newNd, pos];};
pos => {
bndNd.intersection.type ← CB.LPos;
EO.CBSwapChsInComps[newCh1.boundary, bndCh, newCh1, 1];
EO.CoSwapChs[CB.INodeDual[bndNd].posComp, bndCh, newCh1];
SELECT whichEnd FROM
neg => {[] ← CB.SideRemoveh[bndCh.boundary, pos];
newNd ← CB.SideAddl[rCB, CB.ItoINode[CTG.NewIn[bndCh, CB.TNeg], refCh], neg];
CB.SetINodeComps[newNd, endCo, CB.INodeDual[bndNd].negComp];};
pos => {[] ← CB.SideRemoveh[bndCh.boundary, neg];
newNd ← CB.SideAddh[rCB, CB.ItoINode[CTG.NewIn[bndCh, CB.TNeg], refCh], neg];
CB.SetINodeComps[newNd, CB.INodeDual[bndNd].negComp, endCo];};
ENDCASE => ERROR;
[] ← CB.SetEnd[newCh1.boundary, CB.INodeDual[bndNd], neg];
[] ← CB.SetEnd[bndCh.boundary, CB.ItoINode[CTG.NewIn[refCh, CB.TEnd], bndCh], pos];
EO.CoSetCornerChs[endCo, refCh, newCh1];
CB.SetUpDuals[newNd, neg];};
ENDCASE => ERROR;
}; --TtoL --
TtoLChk: PUBLIC PROC [refCh: CTG.Channel, whichEnd, lType: CB.Side, endCo: CoTab.Component] RETURNS [BOOL]={
OPEN eCS: endCo.shape.cornerSpaces, eCC: endCo.cornerChannels;
endI: CB.Intersection ← CTG.End[refCh, whichEnd];
IF endI.type # CB.TEnd THEN RETURN [FALSE];
IF NOT CB.ComponentOn[endI.ch.boundary, endCo, whichEnd] THEN RETURN [FALSE];
IF endCo = NIL THEN RETURN [TRUE]; --%%%Temporary: For a weird case%%%--
SELECT lType FROM
neg => SELECT refCh.type FROM
hor => IF whichEnd = neg THEN RETURN [eCC.se = NIL AND eCS.se # NIL] ELSE RETURN[eCC.sw = NIL AND eCS.sw # NIL];
ver => IF whichEnd = neg THEN RETURN [eCC.nw = NIL AND eCS.nw # NIL] ELSE RETURN[eCC.sw = NIL AND eCS.sw # NIL];
ENDCASE => ERROR;
pos => SELECT refCh.type FROM
hor => IF whichEnd = neg THEN RETURN [eCC.ne = NIL AND eCS.ne # NIL] ELSE RETURN[eCC.nw = NIL AND eCS.nw # NIL];
ver => IF whichEnd = neg THEN RETURN [eCC.ne = NIL AND eCS.ne # NIL] ELSE RETURN[eCC.se = NIL AND eCS.se # NIL];
ENDCASE => ERROR;
ENDCASE => ERROR;
}; --TtoLChk --
LtoT: PUBLIC PROC [refCh: CTG.Channel, whichEnd: CB.Side] RETURNS [posCh: CTG.Channel, lType: CB.Side, endCo: CoTab.Component]={
rCB: CB.Ref ← refCh.boundary;
bndNd: CB.IntersectionNode ← CB.GetEnd[rCB, whichEnd];
negCh: CTG.Channel;
IF LtoTChk[refCh, whichEnd] THEN NULL ELSE ERROR InvalidArgs[$LtoT];
SELECT bndNd.intersection.type FROM
CB.LNeg => {lType ← neg;
negCh ← bndNd.intersection.ch;
SELECT whichEnd FROM
neg => {posCh ← CB.NthIntersection[rCB, pos, 1].ch;
endCo ← CB.NthComponent[rCB, pos, 1];
CB.DestroyINode[CB.SideRemovel[rCB, pos]];};
pos => {posCh ← CB.NthIntersection[rCB, pos, -1].ch;
endCo ← CB.NthComponent[rCB, pos, -1];
CB.DestroyINode[CB.SideRemoveh[rCB, pos]];};
ENDCASE => ERROR;
EO.CoClearCornerChs[endCo, refCh, negCh];};
CB.LPos => {lType ← pos;
posCh ← bndNd.intersection.ch;
SELECT whichEnd FROM
neg => {negCh ← CB.NthIntersection[rCB, neg, 1].ch;
endCo ← CB.NthComponent[rCB, neg, 1];
CB.DestroyINode[CB.SideRemovel[rCB, neg]];};
pos => {negCh ← CB.NthIntersection[rCB, neg, -1].ch;
endCo ← CB.NthComponent[rCB, neg, -1];
CB.DestroyINode[CB.SideRemoveh[rCB, neg]];};
ENDCASE => ERROR;
EO.CoClearCornerChs[endCo, refCh, posCh];};
ENDCASE => ERROR;
bndNd.intersection.type ←CB.TEnd;
SELECT whichEnd FROM
neg => {CB.SetINodeComps[CB.INodeDual[bndNd], CB.NthComponent[negCh.boundary, pos, -1], CB.NthComponent[posCh.boundary, pos, 1]];
[] ← CB.SideAddh[negCh.boundary, CB.INodeDual[bndNd], pos];};
pos => {CB.SetINodeComps[CB.INodeDual[bndNd], CB.NthComponent[negCh.boundary, neg, -1], CB.NthComponent[posCh.boundary, neg, 1]];
[] ← CB.SideAddh[negCh.boundary, CB.INodeDual[bndNd], neg];};
ENDCASE => ERROR;
EO.CBSwapChsInComps[posCh.boundary, posCh, negCh];
CB.Merge[negCh.boundary, posCh.boundary, negCh];
}; -- LtoT--
LtoTChk: PUBLIC PROC[refCh: CTG.Channel, whichEnd: CB.Side] RETURNS [BOOL]={
otherCh: CTG.Channel;
SELECT CTG.End[refCh, whichEnd].type FROM
CTG.LNeg => otherCh ← CTG.NthIntersection[refCh, pos, - BO.PTToInt[whichEnd]].ch;
CTG.LPos => otherCh ← CTG.NthIntersection[refCh, neg, - BO.PTToInt[whichEnd]].ch;
CTG.TEnd => RETURN [FALSE];
ENDCASE => ERROR;
IF otherCh = NIL OR EO.CrossIn[refCh, otherCh]
THEN RETURN [FALSE]
ELSE RETURN [TRUE];
}; --LtoTChk --
FlexKnee: PUBLIC PROC [leg, floor: CTG.Channel, whichEnd, whichDirection: CB.Side, newCh1: CTG.Channel]={
IF FlexKneeChk[leg, floor, whichEnd, whichDirection] THEN NULL ELSE ERROR InvalidArgs[$FlexKnee];
BEGIN
lCB: CB.Ref ← leg.boundary;
tEndNd: CB.IntersectionNode ← CB.GetEnd[lCB, whichEnd];
tEndDual: CB.IntersectionNode ← CB.INodeDual[tEndNd];
tEndCh: CTG.Channel ← tEndNd.intersection.ch;
parent: CoTab.Component ← CB.NthComponent[lCB, BO.PTNot[whichDirection], -BO.PTToInt[whichEnd]];
cornerType: CoTab.CornerTypes ← IF leg.type = hor
THEN BO.CTFromPTs[hor: BO.PTNot[whichEnd], ver: whichDirection]
ELSE BO.CTFromPTs[hor: whichDirection, ver: BO.PTNot[whichEnd]];
sideToOpen: CB.Side ← BO.PTNot[whichEnd];
negBnd, posBnd: CTG.Channel;
IF whichDirection= neg
THEN {negBnd ← floor; posBnd ← leg}
ELSE {negBnd ← leg; posBnd ← floor};
EO.OpenHole1[tEndCh, newCh1, negBnd, posBnd, sideToOpen];
EO.CBSwapChsInComps[newCh1.boundary, tEndCh, newCh1];
SELECT tEndCh.type FROM
hor => IF sideToOpen = pos THEN EO.CoInsert2[parent, tEndCh, posBnd, newCh1, negBnd] ELSE EO.CoInsert2[parent, newCh1, posBnd, tEndCh, negBnd];
ver => IF sideToOpen = pos THEN EO.CoInsert2[parent, negBnd, newCh1, posBnd, tEndCh] ELSE EO.CoInsert2[parent, negBnd, tEndCh, posBnd, newCh1];
ENDCASE => ERROR;
CB.DestroyINode[CB.SideRem2[tEndCh.boundary, tEndDual, parent]];
CB.DestroyINode[IF whichEnd = neg THEN CB.SideRemovel[lCB, whichDirection] ELSE CB.SideRemoveh[lCB, whichDirection]];
EO.MakeLCorner[leg, newCh1, cornerType];
EO.CoSwapChs[parent, leg, floor];
EO.CoSetCornerChs[parent, leg, newCh1];
END;
};--FlexKnee --
FlexKneeChk: PUBLIC PROC [leg, floor: CTG.Channel, whichEnd, whichDirection: CB.Side] RETURNS [BOOL]={
parent: CoTab.Component ← CTG.NthComponent[leg, BO.PTNot[whichDirection], -BO.PTToInt[whichEnd]];
sideToOpen: CB.Side ← BO.PTNot[whichEnd];
corner: CoTab.CornerTypes ← IF leg.type = hor
THEN BO.CTFromPTs[hor: BO.PTNot[whichEnd], ver: whichDirection]
ELSE BO.CTFromPTs[hor: whichDirection, ver: BO.PTNot[whichEnd]];
tEndCh: CTG.Channel ← CTG.End[leg, whichEnd].ch;
negBnd, posBnd: CTG.Channel;
IF CoTab.GetCornerSp[parent, corner] = NIL OR CoTab.GetCornerChs[parent, corner] # NIL THEN RETURN [FALSE];
IF CTG.End[leg, whichEnd].type # CB.TEnd THEN RETURN [FALSE];
IF NOT CTG.ArmOn[tEndCh, floor, sideToOpen] THEN RETURN [FALSE];
IF whichDirection = neg
THEN {negBnd ← floor; posBnd ← leg}
ELSE {negBnd ← leg; posBnd ← floor};
IF CTG.InCount[tEndCh, negBnd, sideToOpen] < CTG.InCount[tEndCh, posBnd, sideToOpen] THEN NULL ELSE RETURN [FALSE];
IF EO.CrossIn[tEndCh, negBnd]
THEN RETURN [EO.XCount[tEndCh, posBnd] = EO.XCount[tEndCh, negBnd] + 1]
ELSE RETURN [EO.XCount[tEndCh, posBnd] = EO.XCount[tEndCh, negBnd]];
};--FlexKneeChk --
ExtendKnee: PUBLIC PROC [shin: CTG.Channel] RETURNS [leg, floor: CTG.Channel, whichEnd, whichDirection: CB.Side]={
IF ExtendKneeChk[shin] THEN NULL ELSE ERROR InvalidArgs[$ExtendKnee];
BEGIN
sCB: CB.Ref ← shin.boundary;
tEnd: CB.Side ← IF CTG.End[shin, neg].type = CB.TEnd THEN neg ELSE pos;
lEndNd: CB.IntersectionNode ← CB.GetEnd[sCB, BO.PTNot[tEnd]];
lEndDual: CB.IntersectionNode ← CB.INodeDual[lEndNd];
lType: CB.IntersectionType ← lEndNd.intersection.type;
parent: CoTab.Component ← CB.SideGetComp[sCB, BO.PTFromInt[- lType]];
cornerType: CoTab.CornerTypes ← CoTab.FindCornerType[parent, shin];
edgeType: CoTab.EdgeTypes ← BO.CTResolveFor[cornerType, BO.OTFlip[shin.type]];
rotDirectn: INTBO.PTToInt[BO.CTFindRotDirectn[cornerType, shin.type]];
chToAttach, negBnd, posBnd: CTG.Channel;
sideToAttach: CB.Side;
newLegNd, newLegDual: CB.IntersectionNode;
leg ← lEndNd.intersection.ch;
floor ← CB.GetEnd[sCB, tEnd].intersection.ch;
whichDirection ← BO.PTFromInt[CB.INodeDual[lEndNd].intersection.type];
whichEnd ← BO.CTInvDirectnFor[cornerType, leg.type];
edgeType ← CoTab.FindEdgeType[parent, floor];
CoTab.SetCornerChs[parent, cornerType, NIL];
lEndNd.intersection.type ← CB.TEnd;
lEndDual.intersection.type ← BO.PTToInt[whichDirection];
CB.SetINodeComp[lEndDual, CTG.NthComponent[leg, whichDirection, lType], BO.PTNot[whichEnd]];
IF whichEnd = neg
THEN [] ← CB.SideAddl[leg.boundary, lEndDual, whichDirection]
ELSE [] ← CB.SideAddh[leg.boundary, lEndDual, whichDirection];
IF (chToAttach ← CoTab.GetCornerChFor[parent, BO.CTRotate[cornerType, rotDirectn], shin.type]) = NIL
THEN {chToAttach ← CoTab.GetPrinCh[parent, BO.ETRotate[edgeType, rotDirectn]]; [negBnd, posBnd, sideToAttach] ← EO.CoGetBndChsAndSide[parent, chToAttach]}
ELSE {[negBnd, posBnd, sideToAttach] ← EO.CoGetBndChsAndSide2[parent, chToAttach]};
[newLegNd, newLegDual] ← EO.NewNodesPair[leg, chToAttach, CB.TEnd, - BO.PTToInt[whichEnd]];
[] ← CB.SetEnd[leg.boundary, newLegNd, whichEnd];
CB.SetINodeComp[newLegDual, parent, BO.PTNot[whichDirection]];
[] ← CB.SideInsert[chToAttach.boundary, newLegDual, negBnd, posBnd, sideToAttach];
EO.CBSwapChsInComps[sCB, shin, chToAttach];
IF whichDirection = neg --negBnd and posBnd have different meaning now--
THEN {negBnd ← floor; posBnd ← leg}
ELSE {negBnd ← leg; posBnd ← floor};
EO.CloseHole1[chToAttach, shin, negBnd, posBnd, sideToAttach];
EO.CoSwapChs[parent, floor, leg];
END;
};--ExtendKnee --
ExtendKneeChk: PUBLIC PROC [shin: CTG.Channel] RETURNS [BOOL]={
lType: CB.IntersectionType;
IF (lType ← CTG.End[shin, neg].type) # CB.TEnd AND CTG.End[shin, pos].type = CB.TEnd THEN RETURN [CTG.NoIntersection[shin, BO.PTFromInt[- lType]]];
IF CTG.End[shin, neg].type = CB.TEnd AND (lType ← CTG.End[shin, pos].type) # CB.TEnd THEN RETURN [CTG.NoIntersection[shin, BO.PTFromInt[- lType]]];
RETURN [FALSE]
};--ExtendKneeChk --
InsertCoAtCorner: PUBLIC PROC[host, co: CoTab.Component, corner: CoTab.CornerTypes, newHCh1, newVCh1: CTG.Channel] ={
eNode, eDual1, eDual2: CB.IntersectionNode;
south, east, north, west, ch1, ch2: CTG.Channel;
[south, east, north, west] ← host.prinChannels;
IF InsertCoAtCornerChk[host, co, corner]
THEN NULL ELSE ERROR InvalidArgs[$InsertCoAtCorner];
EO.MakeLCorner[newHCh1, newVCh1, corner];
SELECT corner FROM
sw => {ch1 ← south; ch2 ← west;
[eNode, eDual1] ← EO.NewNodesPair[newVCh1, south, CB.TEnd, CB.TPos];
[] ←CB.SetEnd[newVCh1.boundary, eNode, neg];
EO.ChSetCBComps[newVCh1, co, host];
CB.SetINodeComps[eDual1, co, host];
[eNode, eDual2] ← EO.NewNodesPair[newHCh1, west, CB.TEnd, CB.TPos];
[] ← CB.SetEnd[newHCh1.boundary, eNode, neg];
EO.ChSetCBComps[newHCh1, co, host];
CB.SetINodeComps[eDual2, co, host];};
se => {ch1 ← south; ch2 ← east;
[eNode, eDual1] ← EO.NewNodesPair[newVCh1, south, CB.TEnd, CB.TPos];
[] ←CB.SetEnd[newVCh1.boundary, eNode, neg];
EO.ChSetCBComps[newVCh1, host, co];
CB.SetINodeComps[eDual1, host, co];
[eNode, eDual2] ← EO.NewNodesPair[newHCh1, east, CB.TEnd, CB.TNeg];
[] ← CB.SetEnd[newHCh1.boundary, eNode, pos];
EO.ChSetCBComps[newHCh1, co, host];
CB.SetINodeComps[eDual2, co, host];};
ne => {ch1 ← north; ch2 ← east;
[eNode, eDual1] ← EO.NewNodesPair[newVCh1, north, CB.TEnd, CB.TNeg];
[] ←CB.SetEnd[newVCh1.boundary, eNode, pos];
EO.ChSetCBComps[newVCh1, host, co];
CB.SetINodeComps[eDual1, host, co];
[eNode, eDual2] ← EO.NewNodesPair[newHCh1, east, CB.TEnd, CB.TNeg];
[] ← CB.SetEnd[newHCh1.boundary, eNode, pos];
EO.ChSetCBComps[newHCh1, host, co];
CB.SetINodeComps[eDual2, host, co];};
nw => {ch1 ← north; ch2 ← west;
[eNode, eDual1] ← EO.NewNodesPair[newVCh1, north, CB.TEnd, CB.TNeg];
[] ←CB.SetEnd[newVCh1.boundary, eNode, pos];
EO.ChSetCBComps[newVCh1, co, host];
CB.SetINodeComps[eDual1, co, host];
[eNode, eDual2] ← EO.NewNodesPair[newHCh1, west, CB.TEnd, CB.TPos];
[] ← CB.SetEnd[newHCh1.boundary, eNode, neg];
EO.ChSetCBComps[newHCh1, host, co];
CB.SetINodeComps[eDual2, host, co];};
ENDCASE => ERROR;
EO.CoInsertNode[host, eDual1, ch1];
EO.CoInsertNode[host, eDual2, ch2];
SELECT corner FROM
sw => EO.CoInsert[co, south, newVCh1, newHCh1, west];
se => EO.CoInsert[co, south, east, newHCh1, newVCh1];
ne => EO.CoInsert[co, newHCh1, east, north, newVCh1];
nw => EO.CoInsert[co, newHCh1, newVCh1, north, west];
ENDCASE => ERROR;
EO.CoSetCornerChs[host, newHCh1, newVCh1]; --can be sped up--
}; --CoCornerInsertComp--
InsertCoAtCornerChk: PUBLIC PROC[host, co: CoTab.Component, corner: CoTab.CornerTypes] RETURNS [BOOL] ={
OPEN pCS: host.shape.cornerSpaces, pCC: host.cornerChannels;
SELECT corner FROM
sw => RETURN [pCS.sw # NIL AND pCC.sw = NIL];
se => RETURN [pCS.se # NIL AND pCC.se = NIL];
ne => RETURN [pCS.ne # NIL AND pCC.ne = NIL];
nw => RETURN [pCS.nw # NIL AND pCC.nw = NIL];
ENDCASE => ERROR;
}; --InsertCoAtCornerChk--
RemoveCoAtCorner: PUBLIC PROC[host: CoTab.Component, corner: CoTab.CornerTypes] RETURNS [co: CoTab.Component, horCh, verCh: CTG.Channel]={
hEdge, vEdge: CoTab.EdgeTypes;
hSide, vSide: CB.Side;
IF RemoveCoAtCornerChk[host, corner] THEN NULL ELSE ERROR InvalidArgs[$RemoveCoAtCorner];
[horCh, verCh] ← CoTab.GetCornerChs[host, corner]^;
CoTab.SetCornerChs[host, corner, NIL];
[hEdge, vEdge] ← BO.CTResolve[corner];
[hSide, vSide] ← BO.CTInvDirectn[corner];
co ←CB.SideGetComp[verCh.boundary, BO.PTNot[hSide]];
CB.DestroyINode[CB.SideRem[CoTab.GetPrinCh[host, hEdge].boundary, verCh, vSide, host]];
CB.DestroyINode[CB.SideRem[CoTab.GetPrinCh[host, vEdge].boundary, horCh, hSide, host]];
};--RemoveCoAtCorner --
RemoveCoAtCornerChk: PUBLIC PROC[host: CoTab.Component, corner: CoTab.CornerTypes] RETURNS [BOOL]={
cChs: CoTab.CornerChannels ← CoTab.GetCornerChs[host, corner];
hDirectn, vDirectn: BO.PolarityTypes;
IF cChs = NIL THEN RETURN [FALSE];
[hDirectn, vDirectn] ← BO.CTDirectn[corner];
IF NOT (CTG.End[cChs.hor, hDirectn].type = CB.TEnd AND CTG.End[cChs.ver, vDirectn].type = CB.TEnd) THEN RETURN [FALSE];
IF EO.NoIntersection[cChs.hor] AND EO.NoIntersection[cChs.ver] THEN RETURN [TRUE] ELSE RETURN [FALSE];
};--RemoveCoAtCornerChk --
InsertCo1: PUBLIC PROC[co: CoTab.Component, chToSplit, negBnd, posBnd: CTG.Channel, sideToOpHint: CB.Side, newCh1: CTG.Channel] RETURNS [sideToClHint: CB.Side]= {
IF InsertCo1Chk[co, chToSplit, negBnd, posBnd] THEN NULL ELSE ERROR InvalidArgs [$InsertCo1];
SELECT sideToOpHint FROM
neg => IF CTG.ArmOn[chToSplit, negBnd, neg] AND CTG.ArmOn[chToSplit, posBnd, neg] THEN NULL ELSE sideToOpHint ← pos;
pos => IF CTG.ArmOn[chToSplit, negBnd, pos] AND CTG.ArmOn[chToSplit, posBnd, pos] THEN NULL ELSE sideToOpHint ← neg;
ENDCASE => ERROR;
EO.OpenHole1[chToSplit, newCh1, negBnd, posBnd, sideToOpHint];
EO.CBSwapChsInComps[newCh1.boundary, chToSplit, newCh1];
SELECT chToSplit.type FROM
hor => IF sideToOpHint = pos THEN EO.CoInsert[co, chToSplit, posBnd, newCh1, negBnd] ELSE EO.CoInsert[co, newCh1, posBnd, chToSplit, negBnd];
ver => IF sideToOpHint = pos THEN EO.CoInsert[co, negBnd, newCh1, posBnd, chToSplit] ELSE EO.CoInsert[co, negBnd, chToSplit, posBnd, newCh1];
ENDCASE => ERROR;
RETURN [sideToOpHint];
}; --InsertCo1--
InsertCo1Chk: PUBLIC PROC[co: CoTab.Component, chToSplit, negBnd, posBnd: CTG.Channel] RETURNS [BOOL]= {
cCB: CB.Ref ← chToSplit.boundary;
IF NOT EO.BndsOkChk[chToSplit, negBnd, posBnd] THEN RETURN [FALSE];
SELECT TRUE FROM
CB.ArmOn[cCB, negBnd, neg] AND CB.ArmOn[cCB, posBnd, neg] => IF CB.InCount[cCB, negBnd, neg] < CB.InCount[cCB, posBnd, neg] THEN NULL ELSE RETURN [FALSE];
CB.ArmOn[cCB, negBnd, pos] AND CB.ArmOn[cCB, posBnd, pos] => IF CB.InCount[cCB, negBnd, pos] < CB.InCount[cCB, posBnd, pos] THEN NULL ELSE RETURN [FALSE];
ENDCASE => RETURN[FALSE];
IF EO.CrossIn[chToSplit, negBnd]
THEN RETURN [EO.XCount[chToSplit, posBnd] = EO.XCount[chToSplit, negBnd] + 1]
ELSE RETURN [EO.XCount[chToSplit, posBnd] = EO.XCount[chToSplit, negBnd]]
}; --InsertCo1Chk--
RemoveCo1: PUBLIC PROC[co: CoTab.Component, shrinkDirectn: BO.OrientationTypes, sideToClHint: CB.Side] RETURNS [mainCh, negBnd, posBnd, sideCh: CTG.Channel, sideToOpHint: CB.Side] --mainCh ~ chToSplit; sideCh ~newCh1 -- = {
negCh, posCh: CTG.Channel;
IF RemoveCo1Chk[co, shrinkDirectn] THEN NULL ELSE ERROR InvalidArgs[$RemoveCo1];
IF shrinkDirectn = hor
THEN {negCh ← CoTab.GetPrinCh[co, west]; posCh ← CoTab.GetPrinCh[co, east];
negBnd ← CoTab.GetPrinCh[co, south]; posBnd ← CoTab.GetPrinCh[co, north];}
ELSE {negCh ← CoTab.GetPrinCh[co, south]; posCh ← CoTab.GetPrinCh[co, north];
negBnd ← CoTab.GetPrinCh[co, west]; posBnd ← CoTab.GetPrinCh[co, east];};
SELECT sideToClHint FROM
neg => IF EO.AreTEndChs[negCh, negBnd, posBnd] THEN NULL ELSE sideToClHint ← pos;
pos => IF EO.AreTEndChs[posCh, negBnd, posBnd] THEN NULL ELSE sideToClHint ← neg;
ENDCASE => ERROR;
IF sideToClHint = pos
THEN {mainCh ← negCh; sideCh ← posCh}
ELSE {mainCh ← posCh; sideCh ← negCh};
EO.CBSwapChsInComps[sideCh.boundary, sideCh, mainCh];
EO.CloseHole1[mainCh, sideCh, negBnd, posBnd, sideToClHint];
sideToOpHint ← sideToClHint;
}; --RemoveCo1--
RemoveCo1Chk: PUBLIC PROC[co: CoTab.Component, shrinkDirectn: BO.OrientationTypes] RETURNS [BOOL]= {
ct: CoTab.CornerTypes ← sw;
negCh, posCh, negBnd, posBnd: CTG.Channel;
THROUGH [0..4) DO
IF CoTab.GetCornerChs[co, ct] # NIL THEN RETURN [FALSE];
ct ← BO.CTRotate[ct];
ENDLOOP;
IF shrinkDirectn = hor
THEN {negCh ← CoTab.GetPrinCh[co, west]; posCh ← CoTab.GetPrinCh[co, east];
negBnd ← CoTab.GetPrinCh[co, south]; posBnd ← CoTab.GetPrinCh[co, north];}
ELSE {negCh ← CoTab.GetPrinCh[co, south]; posCh ← CoTab.GetPrinCh[co, north];
negBnd ← CoTab.GetPrinCh[co, west]; posBnd ← CoTab.GetPrinCh[co, east];};
IF EO.AreTEndChs[negCh, negBnd, posBnd] THEN RETURN [TRUE];
IF EO.AreTEndChs[posCh, negBnd, posBnd] THEN RETURN [TRUE];
RETURN [FALSE];}; --RemoveCo1Chk--
InsertCo2: PUBLIC PROC[co: CoTab.Component, chToSplit, negBnd, posBnd: CTG.Channel, sideToOpHint: CB.Side, newCh1: CTG.Channel] RETURNS [sideToClHint: CB.Side]= {
IF InsertCo2Chk[co, chToSplit, negBnd, posBnd] THEN NULL ELSE ERROR InvalidArgs [$InsertCo2];
SELECT sideToOpHint FROM
neg => IF CTG.ArmOn[chToSplit, negBnd, neg] AND CTG.ArmOn[chToSplit, posBnd, pos] THEN NULL ELSE sideToOpHint ← pos;
pos => IF CTG.ArmOn[chToSplit, negBnd, pos] AND CTG.ArmOn[chToSplit, posBnd, neg] THEN NULL ELSE sideToOpHint ← neg;
ENDCASE => ERROR;
EO.OpenHole2[chToSplit, newCh1, negBnd, posBnd, sideToOpHint];
EO.CBSwapChsInComps[newCh1.boundary, chToSplit, newCh1, 1];
EO.CoSwapChs[CTG.NthComponent[newCh1, sideToOpHint, 1], chToSplit, newCh1];
SELECT chToSplit.type FROM
hor => IF sideToOpHint = pos THEN EO.CoInsert[co, chToSplit, posBnd, newCh1, negBnd] ELSE EO.CoInsert[co, newCh1, posBnd, chToSplit, negBnd];
ver => IF sideToOpHint = pos THEN EO.CoInsert[co, negBnd, newCh1, posBnd, chToSplit] ELSE EO.CoInsert[co, negBnd, chToSplit, posBnd, newCh1];
ENDCASE => ERROR;
RETURN [sideToOpHint];
}; --InsertCo2--
InsertCo2Chk: PUBLIC PROC[co: CoTab.Component, chToSplit, negBnd, posBnd: CTG.Channel] RETURNS [BOOL]= {
cCB: CB.Ref ← chToSplit.boundary;
IF NOT EO.BndsOkChk[chToSplit, negBnd, posBnd] THEN RETURN [FALSE];
SELECT TRUE FROM
CB.ArmOn[cCB, negBnd, neg] AND CB.ArmOn[cCB, posBnd, pos] => NULL;
CB.ArmOn[cCB, negBnd, pos] AND CB.ArmOn[cCB, posBnd, neg] => NULL;
ENDCASE => RETURN[FALSE];
IF EO.CrossIn[chToSplit, negBnd]
THEN RETURN [EO.XCount[chToSplit, posBnd] = EO.XCount[chToSplit, negBnd] + 1]
ELSE RETURN [EO.XCount[chToSplit, posBnd] = EO.XCount[chToSplit, negBnd]]
}; --InsertCo2Chk--
RemoveCo2: PUBLIC PROC[co: CoTab.Component, shrinkDirectn: BO.OrientationTypes, sideToClHint: CB.Side] RETURNS [mainCh, negBnd, posBnd, sideCh: CTG.Channel, sideToOpHint: CB.Side] --mainCh ~ chToSplit; sideCh ~newCh1 -- = {
negCh, posCh: CTG.Channel;
IF RemoveCo2Chk[co, shrinkDirectn] THEN NULL ELSE ERROR InvalidArgs[$RemoveCo2];
IF shrinkDirectn = hor
THEN {negCh ← CoTab.GetPrinCh[co, west]; posCh ← CoTab.GetPrinCh[co, east];
negBnd ← CoTab.GetPrinCh[co, south]; posBnd ← CoTab.GetPrinCh[co, north];}
ELSE {negCh ← CoTab.GetPrinCh[co, south]; posCh ← CoTab.GetPrinCh[co, north];
negBnd ← CoTab.GetPrinCh[co, west]; posBnd ← CoTab.GetPrinCh[co, east];};
SELECT sideToClHint FROM
neg => IF EO.IsTEndCh[negCh, negBnd] AND EO.IsTEndCh[posCh, posBnd] THEN NULL ELSE sideToClHint ← pos;
pos => IF EO.IsTEndCh[posCh, negBnd] AND EO.IsTEndCh[negCh, posBnd] THEN NULL ELSE sideToClHint ← neg;
ENDCASE => ERROR;
IF sideToClHint = pos
THEN {mainCh ← negCh; sideCh ← posCh}
ELSE {mainCh ← posCh; sideCh ← negCh};
EO.CBSwapChsInComps[sideCh.boundary, sideCh, mainCh];
EO.CloseHole2[mainCh, sideCh, negBnd, posBnd, sideToClHint];
sideToOpHint ← sideToClHint;
}; --RemoveCo2--
RemoveCo2Chk: PUBLIC PROC[co: CoTab.Component, shrinkDirectn: BO.OrientationTypes] RETURNS [BOOL]= {
ct: CoTab.CornerTypes ← sw;
negCh, posCh, negBnd, posBnd: CTG.Channel;
THROUGH [0..4) DO
IF CoTab.GetCornerChs[co, ct] # NIL THEN RETURN [FALSE];
ct ← BO.CTRotate[ct];
ENDLOOP;
IF shrinkDirectn = hor
THEN {negCh ← CoTab.GetPrinCh[co, west]; posCh ← CoTab.GetPrinCh[co, east];
negBnd ← CoTab.GetPrinCh[co, south]; posBnd ← CoTab.GetPrinCh[co, north];}
ELSE {negCh ← CoTab.GetPrinCh[co, south]; posCh ← CoTab.GetPrinCh[co, north];
negBnd ← CoTab.GetPrinCh[co, west]; posBnd ← CoTab.GetPrinCh[co, east];};
IF EO.IsTEndCh[negCh, negBnd] AND EO.IsTEndCh[posCh, posBnd] THEN RETURN [TRUE];
IF EO.IsTEndCh[negCh, posBnd] AND EO.IsTEndCh[posCh, negBnd] THEN RETURN [TRUE];
RETURN [FALSE];}; --RemoveCo2Chk--
END.
--Change Log
--This is a bug fix: to handle a case not thought of earlier
-- changes to: FormZChk-> Construct EO.CoXingCount to
-- solve this sticky problem IPEditPrimitivesImpl