GriffinObjectImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Edited by: Maureen Stone, June 14, 1983 10:43 am
Last Edited by: Ken Pier, November 13, 1985 4:46:27 pm PST
DIRECTORY
GriffinData USING [DataRec],
GriffinEncoding USING [AppendLink, EncodeCubicLink, EncodeEdge, EncodeLinearLink, Link, PointForSelectToken, RemoveLastLink],
GriffinKernel USING [DataRec],
GriffinObject USING [ClusterID, EncodeObject, Link, Object, ObjectHandle, ObjectProc, ObjPt, ObjectType, openCluster, PlotOneObject, TokenType, Trajectory],
GriffinPoint USING [ObjPtSequence, ObjPtSequenceRec, ObjToScr, ScrPt, ScrRealToScr, ScrToObj, X, Y],
GriffinViewer USING [SetNewVersion],
Rope USING [ROPE];
GriffinObjectImpl: CEDAR PROGRAM
IMPORTS GriffinEncoding, GriffinObject, GriffinPoint, GriffinViewer
EXPORTS GriffinKernel, GriffinObject = BEGIN
ROPE: TYPE = Rope.ROPE;
Data: TYPE = REF DataRec;
DataRec: PUBLIC TYPE = GriffinData.DataRec; --exported to GriffinKernel
selectTokenSize: INT = 5;
tokenSize: INT = 4;
X: NAT = GriffinPoint.X;
Y: NAT = GriffinPoint.Y;
Visible: PUBLIC PROC [object: GriffinObject.ObjectHandle] RETURNS [BOOLEAN] = {
nData: Data ← object.data;
IF ~object.visible OR object.deleted OR object.cull=outside OR object.view#nData.currentView THEN RETURN[FALSE] ELSE RETURN[TRUE];
};
GetNextClusterID: PUBLIC PROC [data: Data] RETURNS [id: GriffinObject.ClusterID ← 1023] = {
GetID: GriffinObject.ObjectProc = {
IF object.cluster > id THEN id ← object.cluster;
};
id ← GriffinObject.openCluster; --[0..openCluster] are reserved
ForAllObjects[data, GetID];
RETURN[id+1];
};
ForAllObjects: PUBLIC PROC [data: Data, proc: GriffinObject.ObjectProc] = {
rover, next: GriffinObject.ObjectHandle;
rover ← data.headObject.link;
UNTIL rover = data.tailObject DO
next ← rover.link;
IF proc [rover] THEN EXIT;
rover ← next;
ENDLOOP;
};
ForAllObjectsReversed: PUBLIC PROC [data: Data, proc: GriffinObject.ObjectProc] = {
rover, next: GriffinObject.ObjectHandle;
rover ← data.tailObject;
UNTIL rover = data.headObject DO
next ← rover.backLink;
IF proc [rover] THEN EXIT;
rover ← next;
ENDLOOP;
};
ForAllPictureObjects: PUBLIC PROC [data: Data, proc: GriffinObject.ObjectProc] = {
Filter: GriffinObject.ObjectProc = {
IF object.objectType=shape OR object.objectType=caption THEN RETURN[proc [object]]
};
ForAllObjects[data, Filter];
};
ForAllVisibleObjects: PUBLIC PROC [data: Data, proc: GriffinObject.ObjectProc] = {
Filter: GriffinObject.ObjectProc = {
IF Visible[object] THEN RETURN[proc [object]]
};
ForAllObjects[data, Filter];
};
ForAllVisiblePictureObjects: PUBLIC PROC [data: Data, proc: GriffinObject.ObjectProc] = {
Filter: GriffinObject.ObjectProc = {
IF Visible[object] THEN RETURN[proc [object]]
};
ForAllPictureObjects[data, Filter];
};
ForAllObjectsThroughObject: PUBLIC PROC [data: Data, proc: GriffinObject.ObjectProc,
lastObject: GriffinObject.ObjectHandle] = {
rover, next: GriffinObject.ObjectHandle;
rover ← data.headObject.link;
UNTIL rover = data.tailObject DO
next ← rover.link;
IF rover = lastObject THEN next ← data.tailObject;
IF proc [rover] THEN EXIT;
rover ← next;
ENDLOOP;
};
GetTopPictureObj: PUBLIC PROC [data: Data] RETURNS [top: GriffinObject.ObjectHandle] = {
top ← data.tailObject.backLink;
UNTIL top.objectType = caption OR top.objectType = shape DO
top ← top.backLink;
ENDLOOP;
};
GetNextObject: PUBLIC PROC [object: GriffinObject.ObjectHandle] RETURNS [GriffinObject.ObjectHandle] = {
next: GriffinObject.ObjectHandle ← NIL;
IF object=NIL THEN RETURN[next];
next ← object.link;
UNTIL next=NIL OR Visible[next] DO next ← next.link ENDLOOP;
RETURN[next];
};
ForAllInCluster: PUBLIC PROC [data: Data, id: GriffinObject.ClusterID, proc: GriffinObject.ObjectProc] = {
InCluster: GriffinObject.ObjectProc = {
IF object.cluster=id THEN RETURN[proc[object]];
};
ForAllPictureObjects[data, InCluster];
};
ForAllInBoxDo: PUBLIC PROC [data: Data, tl, br: GriffinPoint.ScrPt, proc: GriffinObject.ObjectProc] RETURNS [BOOLEAN] = {
Inside: GriffinObject.ObjectProc = {
IF BoxInsideBox[object.tl, object.br, ntl, nbr] THEN {
hit ← TRUE; RETURN[proc[object]];
};
};
hit: BOOLEANFALSE;
ntl, nbr: GriffinPoint.ScrPt ← tl;
ntl[X] ← MIN[br[X], tl[X]];
ntl[Y] ← MAX[br[Y], tl[Y]];
nbr[X] ← MAX[br[X], tl[X]];
nbr[Y] ← MIN[br[Y], tl[Y]];
ForAllVisibleObjects[data, Inside];
RETURN[hit];
};
ForAllPictureObjectsInBoxDo: PUBLIC PROC [data: Data, tl, br: GriffinPoint.ScrPt, proc: GriffinObject.ObjectProc] RETURNS [BOOLEAN] = {
Inside: GriffinObject.ObjectProc = {
IF BoxInsideBox[object.tl, object.br, ntl, nbr] THEN {
hit ← TRUE; RETURN[proc[object]];
};
};
hit: BOOLEANFALSE;
ntl, nbr: GriffinPoint.ScrPt ← tl;
ntl[X] ← MIN[br[X], tl[X]];
ntl[Y] ← MAX[br[Y], tl[Y]];
nbr[X] ← MAX[br[X], tl[X]];
nbr[Y] ← MIN[br[Y], tl[Y]];
hit ← FALSE;
ForAllVisiblePictureObjects[data, Inside];
RETURN[hit];
};
first set in second set
BoxInsideBox: PROC [tl0, br0, tl1, br1: GriffinPoint.ScrPt] RETURNS [BOOLEAN] = {
RETURN [tl0[X] IN [tl1[X]..br1[X]] AND br0[X] IN [tl1[X]..br1[X]]
AND tl0[Y] IN [br1[Y]..tl1[Y]] AND br0[Y] IN [br1[Y]..tl1[Y]]];
};
Add a link and make its encoding
AppendLink: PUBLIC PROC [object: REF GriffinObject.Object[shape], link: REF GriffinObject.Link] RETURNS [GriffinEncoding.Link] = TRUSTED {
encoding: GriffinEncoding.Link;
IF object=NIL OR link=NIL THEN ERROR;
WITH objlinks: object.trajectory SELECT FROM
linked => {
IF objlinks.links=NIL THEN objlinks.links ← link
ELSE {
linkptr: REF GriffinObject.Link ← objlinks.links;
UNTIL linkptr.link=NIL DO linkptr ← linkptr.link ENDLOOP;
linkptr.link ← link;
};
};
ENDCASE => ERROR; --could signal bad case
encoding ← IF link.degree=D1 THEN GriffinEncoding.EncodeLinearLink[link.knots]
ELSE GriffinEncoding.EncodeCubicLink[link.knots, object.trajectory.splineType];
object.edgeEncoding ← IF object.edgeEncoding=NIL THEN GriffinEncoding.EncodeEdge[LIST[encoding]]
ELSE GriffinEncoding.AppendLink[object.edgeEncoding, encoding];
object.validEncoding ← TRUE;
RETURN[encoding];
};
RemoveLastLink: PUBLIC PROC [object: REF GriffinObject.Object[shape]] RETURNS [GriffinEncoding.Link] = TRUSTED {
encoding: GriffinEncoding.Link;
WITH objlinks: object.trajectory SELECT FROM
linked => {
IF objlinks.links=NIL THEN ERROR;
IF objlinks.links.link=NIL THEN objlinks.links ← NIL --only one link
ELSE {
prev, lptr: REF GriffinObject.Link;
FOR lptr ← objlinks.links, lptr.link UNTIL lptr.link = NIL DO prev ← lptr; ENDLOOP;
prev.link ← FreeLink[lptr];
};
encoding ← GriffinEncoding.RemoveLastLink[object.edgeEncoding];
object.tl ← GriffinPoint.ScrRealToScr[object.edgeEncoding.tl];
object.br ← GriffinPoint.ScrRealToScr[object.edgeEncoding.br];
};
ENDCASE => ERROR; --better be a linked object
RETURN[encoding];
};
does allocate and links the object in on top
StartObject: PUBLIC PROC [data: Data, type: GriffinObject.ObjectType] RETURNS [GriffinObject.ObjectHandle] = {
object: GriffinObject.ObjectHandle ← AllocateObject[type]; --AllocateObject only gets space, does no assignments
object.data ← data;
object.view ← data.currentView;
LinkObject[object];
RETURN[object];
};
LinkObject: PROC [new: GriffinObject.ObjectHandle] = {
nData: Data;
rover: GriffinObject.ObjectHandle;
IF new=NIL THEN RETURN;
IF (nData ← new.data)=NIL THEN ERROR;
rover ← nData.tailObject;
SELECT new.objectType FROM
menu => NULL;
token, selectToken => -- under menus
UNTIL rover.backLink.objectType=shape
OR rover.backLink.objectType=token
OR rover.backLink.objectType=caption
DO rover ← rover.backLink; ENDLOOP;
shape, caption => -- under runtime objects
UNTIL rover.backLink.objectType=shape OR rover.backLink.objectType=caption
DO rover ← rover.backLink; ENDLOOP;
ENDCASE => ERROR;
InsertAfter[new, rover.backLink];
};
AllocateObject: PROC [type: GriffinObject.ObjectType] RETURNS [object: GriffinObject.ObjectHandle] = {
ENABLE UNWIND => {object ← NIL};
SELECT type FROM
shape => object ← NEW[GriffinObject.Object[shape]];
caption => object ← NEW[GriffinObject.Object[caption]];
token => object ← NEW[GriffinObject.Object[token]];
selectToken => object ← NEW[GriffinObject.Object[selectToken]];
menu => object ← NEW[GriffinObject.Object[menu]];
ENDCASE => ERROR;
};
GetTokenBoundingBox: PUBLIC PROC [token: REF GriffinObject.Object[token]] RETURNS [tl, br: GriffinPoint.ScrPt] = {
pt: GriffinPoint.ScrPt ← GriffinPoint.ObjToScr[token.p0];
tl ← [pt[X]-tokenSize, pt[Y]+tokenSize];
br ← [pt[X]+tokenSize+1, pt[Y]-tokenSize-1];
};
GetSelectTokenBoundingBox: PUBLIC PROC [token: REF GriffinObject.Object[selectToken]] RETURNS [tl, br: GriffinPoint.ScrPt] = {
pt: GriffinPoint.ScrPt ← GriffinPoint.ObjToScr[token.p0];
tl ← [pt[X]-selectTokenSize, pt[Y]+selectTokenSize];
br ← [pt[X]+selectTokenSize+1, pt[Y]-selectTokenSize-1];
};
AddToken: PUBLIC PROC [data: Data, pt: GriffinPoint.ScrPt, type: GriffinObject.TokenType] = {
object: REF GriffinObject.Object[token] ← NARROW[StartObject[data, token]];
object.p0 ← GriffinPoint.ScrToObj[pt];
[object.tl, object.br] ← GetTokenBoundingBox[object];
object.validEncoding ← TRUE;
object.tokenType ← type;
IF type=open THEN object.cluster ← GriffinObject.openCluster; --is always clustered with linkedobj
GriffinObject.PlotOneObject[object];
};
DeleteAllCPs: PUBLIC PROC [data: Data] = {
DeleteCP: GriffinObject.ObjectProc = TRUSTED {
WITH token: object SELECT FROM
token => IF token.tokenType = open OR token.tokenType = CP THEN [] ← DeleteObject[object];
ENDCASE => NULL;
};
ForAllObjects[data, DeleteCP];
};
ReadCPs: PUBLIC PROC [data: Data] RETURNS [array: GriffinPoint.ObjPtSequence ← NIL] =
TRUSTED { ENABLE UNWIND => {array ← NIL};
object: REF GriffinObject.Object ← data.headObject.link;
ntokens: INTEGER ← 0;
UNTIL object = data.tailObject DO
WITH token: object SELECT FROM
token => IF token.tokenType = CP OR token.tokenType = open
THEN ntokens ← ntokens+1;
ENDCASE;
object ← object.link;
ENDLOOP;
IF ntokens=0 THEN RETURN;
array ← NEW[GriffinPoint.ObjPtSequenceRec[ntokens]];
object ← data.headObject.link;
ntokens ← 0;
UNTIL object = data.tailObject DO
WITH token: object SELECT FROM
token => IF token.tokenType = CP OR token.tokenType = open THEN {
array[ntokens] ← token.p0;
ntokens ← ntokens+1;
};
ENDCASE;
object ← object.link;
ENDLOOP;
};
ForAllSelectedDo: PUBLIC PROC [data: Data, proc: GriffinObject.ObjectProc] = {
DoSelected: GriffinObject.ObjectProc = {
IF object.selected = TRUE AND Visible[object] THEN RETURN[proc[object]];
};
ForAllPictureObjects[data, DoSelected];
};
SelectObject: PUBLIC PROC [object: GriffinObject.ObjectHandle] RETURNS [GriffinObject.ObjectHandle]= {
token: REF GriffinObject.Object[selectToken] ← NIL;
IF object=NIL OR object.selected = TRUE OR object.objectType=token OR object.objectType=menu OR object.objectType=selectToken THEN RETURN[NIL];
object.selected ← TRUE;
token ← CreateSelectToken[object];
RETURN[token];
};
LocateSelectToken: PROC [token: REF GriffinObject.Object[selectToken], object: GriffinObject.ObjectHandle] RETURNS [GriffinObject.ObjPt] = TRUSTED {
screenLoc: GriffinPoint.ScrPt ← WITH typedObj: object SELECT FROM
caption => GriffinPoint.ObjToScr[typedObj.p0],
shape => GriffinEncoding.PointForSelectToken[typedObj.edgeEncoding],
ENDCASE => ERROR;
RETURN[GriffinPoint.ScrToObj[screenLoc]];
};
CreateSelectToken: PROC [forObject: GriffinObject.ObjectHandle] RETURNS [token: REF GriffinObject.Object[selectToken]] = {
IF forObject=NIL THEN ERROR; -- added error check. (KAP)
token ← NARROW[StartObject[forObject.data, selectToken]];
token.p0 ← LocateSelectToken[token, forObject];
[token.tl, token.br] ← GetSelectTokenBoundingBox[token];
token.validEncoding ← TRUE;
token.located ← TRUE;
token.selectedObj ← forObject;
token.view ← forObject.view;
token.data ← data; -- performed by StartObject
RETURN[token];
};
DeSelectObject: PUBLIC PROC [object: GriffinObject.ObjectHandle] = {
token: GriffinObject.ObjectHandle;
IF object=NIL OR object.selected = FALSE THEN RETURN;
token ← ReturnSelectToken[object];
object.selected ← FALSE;
IF token=NIL THEN RETURN;
token ← DeleteObject[token];
};
SelectCluster: PUBLIC PROC [data: Data, id: GriffinObject.ClusterID] RETURNS [GriffinObject.ObjectHandle]= {
token: REF GriffinObject.Object[selectToken] ← NIL;
SelectOneObject: GriffinObject.ObjectProc = {
IF object.selected = TRUE OR object.objectType=token OR object.objectType=menu
THEN RETURN[FALSE];
object.selected ← TRUE;
IF token = NIL THEN token ← CreateSelectToken[object];
};
ForAllInCluster[data, id, SelectOneObject];
RETURN[token];
};
DeSelectCluster: PUBLIC PROC [data: Data, id: GriffinObject.ClusterID] = {
token: GriffinObject.ObjectHandle;
tokenFound: BOOLEANFALSE;
DeSelectOneObject: GriffinObject.ObjectProc = {
IF object.selected = FALSE THEN RETURN[FALSE];
object.selected ← FALSE;
IF tokenFound OR (token ← ReturnSelectToken[object]) = NIL
THEN RETURN[FALSE];
token ← DeleteObject[token];
tokenFound ← TRUE;
};
ForAllInCluster[data, id, DeSelectOneObject];
};
ReturnSelectToken: PUBLIC PROC [object: GriffinObject.ObjectHandle] RETURNS [REF GriffinObject.Object[selectToken]] = {
nData: Data ← object.data;
obj: GriffinObject.ObjectHandle;
IF object=NIL THEN ERROR; -- added error check. (KAP)
obj ← nData.headObject.link;
UNTIL obj = nData.tailObject DO
WITH obj SELECT FROM
token: REF GriffinObject.Object[selectToken] => IF token.selectedObj = object THEN RETURN[token];
ENDCASE;
obj ← obj.link;
ENDLOOP;
RETURN[NIL];
};
does a Start object, fills in all the info from the indicated object
doesn't copy selected field or cluster info
CopyObject: PUBLIC PROC [object: GriffinObject.ObjectHandle] RETURNS [GriffinObject.ObjectHandle] = {
nData: Data;
new: GriffinObject.ObjectHandle ← NIL;
IF object=NIL THEN RETURN[NIL];
nData ← object.data;
WITH object SELECT FROM
object: REF GriffinObject.Object[shape] => {
newobj: REF GriffinObject.Object[shape] ← NARROW[StartObject[nData, shape]];
newobj.closed ← object.closed;
newobj.trajectory ← CopyTrajectory[object.trajectory];
newobj.edgeEncoding ← NIL;
newobj.areaEncoding ← NIL;
GriffinObject.EncodeObject[newobj]; --rather than copying the encoding
new ← newobj;
};
object: REF GriffinObject.Object[caption] => {
newobj: REF GriffinObject.Object[caption] ← NARROW[StartObject[nData, caption]];
newobj.p0 ← object.p0;
newobj.text ← object.text;
new ← newobj;
};
object: REF GriffinObject.Object[selectToken] => ERROR;
object: REF GriffinObject.Object[token] => ERROR;
ENDCASE;
new.validEncoding ← TRUE;
new.style ← object.style;
new.cluster ← 0;
new.view ← object.view;
new.deleted ← object.deleted;
new.visible ← object.visible;
new.selected ← FALSE;
new.cull ← object.cull;
new.tl ← object.tl;
new.br ← object.br;
GriffinViewer.SetNewVersion[nData];
RETURN[new];
};
CopyTrajectory: PROC [traj: REF GriffinObject.Trajectory] RETURNS [REF GriffinObject.Trajectory] = {
WITH traj SELECT FROM
type: REF GriffinObject.Trajectory[linked] => {
ptr: REF GriffinObject.Link ← type.links;
firstlink: REF GriffinObject.Link ← NIL;
thislink, newlink: REF GriffinObject.Link;
newtraj: REF GriffinObject.Trajectory[linked] ← NEW [GriffinObject.Trajectory[linked]];
UNTIL ptr=NIL DO
ENABLE UNWIND => newtraj ←NIL;
newlink ← NEW[GriffinObject.Link];
newlink^ ← [NIL, ptr.degree, CopyKnots[ptr.knots]];
IF firstlink=NIL THEN thislink ← firstlink ← newlink
ELSE {
thislink.link ← newlink;
thislink ← newlink;
};
ptr ← ptr.link;
ENDLOOP;
newtraj.splineType ← type.splineType;
newtraj.links ← firstlink;
RETURN[newtraj];
};
type: REF GriffinObject.Trajectory[cyclic] => {
newtraj: REF GriffinObject.Trajectory[cyclic] ← NEW [GriffinObject.Trajectory[cyclic]];
newtraj.splineType ← traj.splineType;
newtraj.knots ← CopyKnots[type.knots];
RETURN[newtraj];
};
ENDCASE;
RETURN [NIL];
};
CopyKnots: PROC [array: GriffinPoint.ObjPtSequence] RETURNS [newarray: GriffinPoint.ObjPtSequence] = {
ENABLE UNWIND => {newarray ← NIL};
newarray ← NEW[GriffinPoint.ObjPtSequenceRec[array.length]];
FOR i: NAT IN [0..array.length) DO newarray[i] ← array[i]; ENDLOOP;
};
SinkObject: PUBLIC PROC [object: GriffinObject.ObjectHandle]= {
nData: Data ← object.data;
IF object.backLink=nData.headObject THEN RETURN; --already on bottom
UnlinkObject[object];
InsertAfter[object, nData.headObject];
};
FloatObject: PUBLIC PROC [object: GriffinObject.ObjectHandle]= {
IF TopPicture[object] THEN RETURN;
remove object
UnlinkObject[object];
LinkObject[object];
};
FlipUpObject: PUBLIC PROC [object: GriffinObject.ObjectHandle] = {
nextobj: GriffinObject.ObjectHandle;
IF TopPicture[object] THEN RETURN;
nextobj ← object.link;
UNTIL Visible[nextobj] OR TopPicture[nextobj] DO nextobj ← nextobj.link; ENDLOOP;
IF ~Visible[nextobj] THEN RETURN; --already top visible
UnlinkObject[object];
insert after next object
InsertAfter[object, nextobj];
};
TopPicture: PROC [object: GriffinObject.ObjectHandle] RETURNS [BOOLEAN] = INLINE
{
RETURN[(object.link.objectType=token OR object.link.objectType=menu)];
};
UnlinkObject: PROC [object: GriffinObject.ObjectHandle] = {
object.backLink.link ← object.link;
object.link.backLink ← object.backLink;
object.link ← NIL;
object.backLink ← NIL;
};
InsertAfter: PROC [object, prevobj: GriffinObject.ObjectHandle] = {
object.link ← prevobj.link;
object.backLink ← prevobj;
prevobj.link ← object;
object.link.backLink ← object;
};
FlipDownObject: PUBLIC PROC [object: GriffinObject.ObjectHandle] = {
nData: Data ← object.data;
prevobj: GriffinObject.ObjectHandle;
IF object.backLink=nData.headObject THEN RETURN; --already on bottom
prevobj ← object.backLink;
UNTIL Visible[prevobj] OR prevobj.backLink=nData.headObject DO
prevobj ← prevobj.backLink;
ENDLOOP;
IF ~Visible[prevobj] THEN RETURN; --already bottom visible object
UnlinkObject[object];
link it in after prevobj.backLink
InsertAfter[object, prevobj.backLink];
};
unlinks object. Set up for undo
DeleteObject: PUBLIC PROC [object: GriffinObject.ObjectHandle] RETURNS [GriffinObject.ObjectHandle] = {
next: GriffinObject.ObjectHandle;
IF object=NIL THEN RETURN[NIL];
next ← object.link;
UnlinkObject[object];
WITH object SELECT FROM
shapeRef: REF GriffinObject.Object[shape] => DeleteShape[shapeRef];
ENDCASE;
RETURN[next];
};
ExpungeObjects: PUBLIC PROC [data: Data] = {
object: GriffinObject.ObjectHandle ← data.headObject;
UNTIL object=NIL DO
IF object.deleted THEN object ← DeleteObject[object]
ELSE object ← object.link;
ENDLOOP;
};
DeleteShape: PROC [shape: REF GriffinObject.Object[shape]] = TRUSTED {
IF shape=NIL THEN RETURN;
shape.edgeEncoding ← NIL;
shape.areaEncoding ← NIL;
WITH type: shape.trajectory SELECT FROM
linked => {
link: REF GriffinObject.Link ← type.links;
UNTIL link=NIL DO
link ← FreeLink[link];
ENDLOOP;
};
cyclic => type.knots ← NIL;
ENDCASE;
shape.trajectory ← NIL;
};
FreeLink: PROC [link: REF GriffinObject.Link] RETURNS [next: REF GriffinObject.Link]= {
next ← link.link;
link.knots ← NIL;
};
InitObjectFns: PUBLIC PROC [data: Data] = {
data.headObject ← AllocateObject[caption];
data.tailObject ← AllocateObject[menu];
data.headObject.data ← data.tailObject.data ← data;
data.headObject.view ← data.tailObject.view ← data.currentView;
data.headObject.visible ← data.tailObject.visible ← FALSE;
data.headObject.validEncoding ← data.tailObject.validEncoding ← TRUE;
data.headObject.cull ← data.tailObject.cull ← outside;
data.headObject.link ← data.tailObject;
data.tailObject.backLink ← data.headObject;
data.headObject.backLink ← NIL;
data.tailObject.link ← NIL;
};
END.