DIRECTORY Atom USING [GetPropFromList], Basics USING [LowHalf], BasicTime USING [GMT, nullGMT], FS USING [Error, StreamOpen], Graph USING [CaretIndex, CaretSpec, ColorIndex, Entity, EntityGroup, EntityGroupList, EntityGroupRec, EntityList, FontIndex, GRAPH, GraphHandle, NestedEntities, NestedEntitiesList, ROPE, SegmentDataList, TargetSpec, Text, Texts, ValueList, XY], GraphConvert USING [VLFromSDL], GraphFileKeys, GraphPrivate USING [CharPair, FourChars, GraphStreamProc, LVL, STREAM], GraphUtil USING [FullName, LengthOfSDL, LengthOfVL, ReverseValueList], IO USING [Close, Error, Flush, PutBlock, PutChar, PutF, real, rope, STREAM], List USING [Kill], Rope USING [IsEmpty, Length, ToRefText]; GraphWrite: CEDAR PROGRAM IMPORTS Atom, Basics, FS, IO, GraphConvert, GraphUtil, List, Rope EXPORTS GraphPrivate = { OPEN Graph, GraphFileKeys, GraphPrivate, GraphUtil; WriteGraphFile: PUBLIC PROC [handle: GraphHandle _ NIL, file: ROPE _ NIL, plottedOnly: BOOL _ TRUE] RETURNS[msg, newName: ROPE _ NIL] = { IF handle = NIL THEN RETURN["handle = NIL IN WriteGraphFile"] ELSE IF file.IsEmpty THEN RETURN ["File name is empty."] ELSE { OPEN handle; ok: BOOL _ TRUE; s: STREAM _ NIL; nVector: CARDINAL _ 0; s _ FS. StreamOpen[fileName: file, accessOptions: $create, keep: 10 ! FS.Error => {msg _ error.explanation; ok _ FALSE; CONTINUE} ]; IF ok THEN { ENABLE IO.Error => { msg _ "Write Error."; CONTINUE }; PutRope[s, "binary graph"]; -- format id PutTexts[s, IF plottedOnly THEN graph.texts ELSE handle.allTexts]; PutCarets[s, graph]; PutByte[s, ShowSlopeKey]; PutBool[s, graph.showSlope]; PutTargets[s, graph]; PutGrids[s, graph]; PutDivisions[s, graph]; PutBounds[s, graph]; PutColors[s, graph]; PutFonts[s, graph]; PutEntityGroupList[s, handle, plottedOnly]; PutByte[s, EndOfRecordKey]; }; IF s # NIL THEN { s.Flush[]; s.Close[]; newName _ NARROW[Atom.GetPropFromList[s.propList, $Name]] }; }; }; -- WriteGraphFile PutTexts: PROC [s: STREAM, texts: Texts] = { PutByte[s, TextsKey]; FOR ts: Texts _ texts, ts.rest UNTIL ts = NIL DO text: Text _ ts.first; PutByte[s, TextKey]; PutByte[s, NameKey]; PutRope[s, text.text]; PutByte[s, PlaceKey]; PutReal[s, text.place.x]; PutReal[s, text.place.y]; PutByte[s, FontIndexKey]; PutByte[s, text.fontIndex]; PutByte[s, ColorIndexKey]; PutByte[s, text.colorIndex]; PutByte[s, RotationKey]; PutReal[s, text.rotation]; PutByte[s, JustificationsKey]; PutByte[s, XKey]; PutByte[s, SELECT text.justifX FROM left => 1, center => 2, ENDCASE => 3]; PutByte[s, YKey]; PutByte[s, SELECT text.justifY FROM top => 1, center => 2, ENDCASE => 3]; PutByte[s, EndOfRecordKey]; PutByte[s, TextIdKey]; PutInt[s, text.id]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutTexts PutCarets: GraphStreamProc = { PutByte[s, CaretsKey]; FOR index: CaretIndex IN CaretIndex DO PutByte[s, SELECT index FROM primary => PrimaryKey, secondary => SecondaryKey, ENDCASE => TextCaretKey]; PutByte[s, PlaceKey]; PutReal[s, graph.caret[index].place.x]; PutReal[s, graph.caret[index].place.y]; PutByte[s, OnKey]; PutBool[s, graph.caret[index].on]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutCarets PutTargets: GraphStreamProc = { PutByte[s, TargetsKey]; FOR xy: XY IN XY DO OPEN graph.target[xy]; PutByte[s, IF xy = x THEN XKey ELSE YKey]; PutByte[s, ValueKey]; PutReal[s, value]; PutByte[s, WidthKey]; PutReal[s, width]; PutByte[s, ColorIndexKey]; PutByte[s, colorIndex]; PutByte[s, OnKey]; PutBool[s, on]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutTargets PutGrids: GraphStreamProc = { PutByte[s, GridsKey]; FOR xy: XY IN XY DO PutByte[s, IF xy = x THEN XKey ELSE YKey]; PutByte[s, OnKey]; PutBool[s, graph.grids[xy]]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutGrids PutDivisions: GraphStreamProc = { PutByte[s, DivisionsKey]; FOR xy: XY IN XY DO PutByte[s, IF xy = x THEN XKey ELSE YKey]; PutByte[s, AutoKey]; PutBool[s, graph.auto[divisions]]; PutByte[s, DivisionsKey]; PutByte[s, graph.division[xy]]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutDivisions PutBounds: GraphStreamProc = { PutByte[s, BoundsKey]; FOR xy: XY IN XY DO OPEN graph.bounds; PutByte[s, IF xy = x THEN XKey ELSE YKey]; PutByte[s, AutoKey]; PutBool[s, graph.auto[bounds]]; PutByte[s, MaxKey]; PutReal[s, IF xy = x THEN xmax ELSE ymax]; PutByte[s, MinKey]; PutReal[s, IF xy = x THEN xmin ELSE ymin]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutBounds PutColors: GraphStreamProc = { PutByte[s, ColorsKey]; FOR i: ColorIndex IN ColorIndex DO OPEN graph.color[i]; PutByte[s, i+1]; PutByte[s, RKey]; PutReal[s, R]; PutByte[s, GKey]; PutReal[s, G]; PutByte[s, BKey]; PutReal[s, B]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutColors PutFonts: GraphStreamProc = { PutByte[s, FontsKey]; FOR i: FontIndex IN FontIndex DO OPEN graph.font[i]; PutByte[s, i+1]; PutByte[s, NameKey]; PutRope[s, family]; PutByte[s, BoldKey]; PutBool[s, bold]; PutByte[s, ItalicKey]; PutBool[s, italic]; PutByte[s, VFontSizeKey]; PutInt[s, vFontSize]; PutByte[s, PFontScaleKey]; PutReal[s, pFontScale]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutFonts PutEntityGroupList: PROC [s: STREAM, handle: GraphHandle, plottedOnly: BOOL _ TRUE] = { PutByte[s, EntityGroupListKey]; FOR egl: EntityGroupList _ handle.entityGroupList, egl.rest UNTIL egl = NIL DO eg: EntityGroup _ egl.first; PutByte[s, EntityGroupKey]; PutEntity[s, eg.x, plottedOnly]; IF plottedOnly THEN PutPlottedNE[s, handle.graph.entityList, eg] ELSE PutAllNE[s, eg.ys]; PutByte[s, GroupIdKey]; PutInt[s, eg.id]; PutByte[s, LengthKey]; PutInt[s, eg.length]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutEntityGroupList PutEntity: PROC [s: STREAM, entity: Entity, plottedOnly: BOOL _ TRUE] = { PutByte[s, EntityKey]; PutByte[s, NameKey]; PutRope[s, IF plottedOnly THEN FullName[entity] ELSE entity.name]; PutByte[s, CommentKey]; PutRope[s, IF plottedOnly THEN "" ELSE entity.comment]; PutByte[s, ColorIndexKey]; PutByte[s, entity.colorIndex]; PutByte[s, MarkKey]; PutByte[s, SELECT entity.mark FROM none => NoneKey, round => RoundKey, square => SquareKey, diamond => DiamondKey, cross => CrossKey, dollar => DollarKey, ENDCASE => PercentKey]; PutByte[s, WidthKey]; PutReal[s, entity.width]; IF plottedOnly THEN PutValuesForSDL[s, entity.segments] ELSE PutValuesForVL[s, entity.oldValues]; PutByte[s, EntityIdKey]; PutInt[s, entity.id]; PutByte[s, EndOfRecordKey]; }; -- PutEntity PutAllEL: PROC [s: STREAM, entityList: EntityList] = { PutByte[s, EntityListKey]; FOR el: EntityList _ entityList, el.rest UNTIL el = NIL DO PutEntity[s, el.first, FALSE]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutAllEL PutPlottedEL: PROC [s: STREAM, entityList: EntityList, group: EntityGroup] = { PutByte[s, EntityListKey]; FOR el: EntityList _ entityList, el.rest UNTIL el = NIL DO IF el.first.group = group THEN PutEntity[s, el.first, TRUE]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutPlottedEL PutPlottedNE: PROC [s: STREAM, plottedEL: EntityList, group: EntityGroup] = { PutByte[s, NestedEntitiesKey]; PutByte[s, NameKey]; PutRope[s, group.ys.name]; PutByte[s, CommentKey]; PutRope[s, group.ys.comment]; PutPlottedEL[s, plottedEL, group]; PutNEL[s, NIL]; PutByte[s, EndOfRecordKey]; }; -- PutPlottedNE PutAllNE: PROC [s: STREAM, ne: NestedEntities] = { PutByte[s, NestedEntitiesKey]; PutByte[s, NameKey]; PutRope[s, ne.name]; PutByte[s, CommentKey]; PutRope[s, ne.comment]; PutAllEL[s, ne.entityList]; PutNEL[s, ne.children]; PutByte[s, EndOfRecordKey]; }; -- PutAllNE PutNEL: PROC [s: STREAM, nestedEL: NestedEntitiesList] = { PutByte[s, NELKey]; FOR nel: NestedEntitiesList _ nestedEL, nel.rest UNTIL nel = NIL DO PutAllNE[s, nel.first]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutNEL PutValuesForVL: PROC [s: STREAM, valueList: ValueList] = { PutByte[s, ValuesKey]; PutInt[s, LengthOfVL[valueList]]; FOR vl: ValueList _ valueList, vl.rest UNTIL vl = NIL DO PutReal[s, vl.first]; ENDLOOP; }; -- PutValuesForVL PutValuesForSDL: PROC [s: STREAM, segmentDataList: SegmentDataList] = { PutByte[s, ValuesKey]; PutInt[s, LengthOfSDL[segmentDataList]]; FOR sdl: SegmentDataList _ segmentDataList, sdl.rest UNTIL sdl = NIL DO PutReal[s, sdl.first.end]; ENDLOOP; }; -- PutValuesForSDL PutCrossSections: PROC [s: STREAM, eg: EntityGroup] = { vllR, vll, tvll: LVL _ NIL; GetVLfromSDL: PROC [segmentDataList: SegmentDataList] RETURNS [vl: ValueList _ NIL] = { FOR sdl: SegmentDataList _ segmentDataList, sdl.rest UNTIL sdl = NIL DO vl _ CONS[sdl.first.end, vl]; ENDLOOP; [vl, ] _ ReverseValueList[vl]; }; -- GetVLfromSDL GetVLsFromNE: PROC [ne: NestedEntities, old: LVL] RETURNS [new: LVL _ NIL] = { new _ old; FOR el: EntityList _ ne.entityList, el.rest UNTIL el = NIL DO new _ CONS[ IF el.first.segments = NIL THEN el.first.oldValues ELSE GetVLfromSDL[el.first.segments], new] ENDLOOP; new _ GetVLsFromNEL[ne.children, new]; }; -- GetVLsFromNE GetVLsFromNEL: PROC [nestedEntitiesList: NestedEntitiesList, old: LVL] RETURNS [new: LVL _ NIL] = { -- result is in reverse order !! new _ old; FOR nel: NestedEntitiesList _ nestedEntitiesList, nel.rest UNTIL nel = NIL DO new _ GetVLsFromNE[nel.first, new]; ENDLOOP; }; -- GetVLsFromNEL CleanUpLVL: PROC [old: LVL] RETURNS [LVL] = { WHILE old # NIL DO next: LVL _ old.rest; old.first _ NIL; old.rest _ NIL; old _ next; ENDLOOP; RETURN[NIL]; }; -- CleanUpLVL vllR _ CONS[GetVLfromSDL[eg.x.segments], NIL]; -- list of vl in reverse order. vllR _ GetVLsFromNE[eg.ys, vllR]; FOR tvll _ vllR, tvll.rest UNTIL tvll = NIL DO vll _ CONS[tvll.first, vll]; ENDLOOP; vllR _ CleanUpLVL[vllR]; PutByte[s, CrossSectionsKey]; IF vll # NIL THEN UNTIL vll.first = NIL DO PutByte[s, TailsKey]; -- keyword before each set of tails FOR tvll _ vll, tvll.rest UNTIL tvll = NIL DO vl: ValueList _ tvll.first; IF vl = NIL THEN EXIT; PutReal[s, vl.first]; tvll.first _ vl.rest; ENDLOOP; ENDLOOP; PutByte[s, EndOfListKey]; vll _ CleanUpLVL[vll]; }; -- PutCrossSections WriteTextFile: PUBLIC PROC [handle: GraphHandle, file: ROPE] RETURNS [msg: ROPE _ NIL] = { IF handle = NIL THEN RETURN["handle is nil"] ELSE IF file.IsEmpty[] THEN RETURN["File name is empty."] ELSE { OPEN handle; s: STREAM _ NIL; s _ FS. StreamOpen[fileName: file, accessOptions: $create, keep: 10 ! FS.Error => { msg _ error.explanation; CONTINUE} ]; IF msg = NIL THEN { ENABLE IO.Error => {msg _ "WriteText Error."; CONTINUE }; s.PutF["-- %g\n", IO.rope[file]]; FOR egl: EntityGroupList _ entityGroupList, egl.rest UNTIL egl = NIL DO group: EntityGroup _ egl.first; plotted: BOOL _ FALSE; FOR el: EntityList _ graph.entityList, el.rest UNTIL el = NIL DO IF el.first.group = group THEN {plotted _ TRUE; EXIT}; ENDLOOP; IF plotted THEN { s.PutF["\nvariables:\n\n\"%g%g\" ", IO.rope[group.x.name], IO.rope[group.x.comment]]; FOR el: EntityList _ graph.entityList, el.rest UNTIL el = NIL DO IF el.first.group = group THEN { s.PutF["\"%g\" ", IO.rope[FullName[el.first]]]; }; ENDLOOP; s.PutF["\n\nvalues:\n\n"]; WriteCrossSections[s, graph.entityList, group]; }; ENDLOOP; }; IF s # NIL THEN {s.Flush[]; s.Close[]}; }; }; -- WriteTextFile WriteCrossSections: PROC [s: IO.STREAM, entityList: EntityList, group: EntityGroup] = { vll, vllLast: LVL _ NIL; FOR el: EntityList _ entityList, el.rest UNTIL el = NIL DO IF el.first.group = group THEN { tvl: LVL _ CONS[GraphConvert.VLFromSDL[el.first.segments], NIL]; IF vllLast = NIL THEN { xvl: LVL _ CONS[GraphConvert.VLFromSDL[group.x.segments], NIL]; vll _ vllLast _ xvl; vllLast.rest _ tvl; vllLast _ tvl; } ELSE {vllLast.rest _ tvl; vllLast _ tvl}; }; ENDLOOP; IF vll # NIL THEN UNTIL vll.first = NIL DO FOR tvl: LVL _ vll, tvl.rest UNTIL tvl = NIL DO vl: ValueList _ tvl.first; IF vl = NIL THEN EXIT; s.PutF[IF tvl.rest = NIL THEN "%g\n" ELSE "%g ", IO.real[vl.first]]; tvl.first _ vl.rest; ENDLOOP; ENDLOOP; TRUSTED{List.Kill[LOOPHOLE[vll]]}; TRUSTED{List.Kill[LOOPHOLE[vllLast]]}; }; -- WriteCrossSections PutRope: PROC [stream: STREAM, rope: ROPE _ NIL] = { length: CARDINAL _ Basics.LowHalf[rope.Length[]]; PutCardinal[stream, length]; stream.PutBlock[Rope.ToRefText[rope], 0, length]; }; -- PutRope PutTime: PROC [stream: STREAM, time: BasicTime.GMT _ BasicTime.nullGMT] = { PutLongWord[stream, LOOPHOLE[time, FourChars]]; }; -- PutTime PutBool: PROC[stream: STREAM, bool: BOOL _ TRUE] = { PutByte[stream, IF bool THEN TrueKey ELSE FalseKey]; }; -- PutBool PutByte: PROC [stream: STREAM, byte: BYTE _ 0] = { stream.PutChar[LOOPHOLE[byte, CHAR]]; }; -- PutByte PutInt: PROC [stream: STREAM, int: INT _ 0] = { PutLongWord[stream, LOOPHOLE[int, FourChars]]; }; -- PutInt PutReal: PROC [stream: STREAM, real: REAL _ 0] = { PutLongWord[stream, LOOPHOLE[real, FourChars]]; }; -- PutReal PutCardinal: PROC [stream: STREAM, word: CARDINAL _ 0] = { pair: CharPair _ LOOPHOLE[word, CharPair]; stream.PutChar[pair.high]; stream.PutChar[pair.low]; }; -- PutCardinal PutLongWord: PROC [stream: STREAM, long: FourChars] = INLINE { stream.PutChar[long.lh]; stream.PutChar[long.ll]; stream.PutChar[long.hh]; stream.PutChar[long.hl]; }; -- PutLongCard }. CHANGE LOG. SChen, created at October 9, 1985 6:21:05 pm PDT. NGraphWrite.mesa, Copyright Σ 1985, 1987 by Xerox Corporation. All rights reserved. Last Edited by: Christian Le Cocq April 27, 1987 5:00:27 pm PDT Sweetsun Chen, November 25, 1985 10:37:35 pm PST ok _ FALSE; PutCrossSections[s, eg]; result is in reverse order !! copy to vll in the correct order. clean up the reversed one. start to work. clean up. write simple data table for the graph first: BOOL _ TRUE; IF first THEN first _ FALSE ELSE s.PutF[", "]; write plotted curves in texts, so caller is responsible to make sure that segments of each entity is not nil. writing routines Κ–˜JšœS™Sšœ™Icode™/K™0—J˜šΟk ˜ Jšœœ˜Jšœœ ˜Jšœ œœ ˜Jšœœ˜Jš œœrœ3œ7œ˜τJšœ œ ˜J˜Jšœ œ(œœ˜GJšœ œ7˜FJšœœ<œ˜LJšœœ˜Jšœœ˜(—J˜šΟn œœ˜Jšœœœ%˜AJšœ˜—J˜Jšœ/˜3J˜šžœœœœœœœœœœœ˜‰Jšœ œœœ"˜=Jšœœœœ˜8šœœ˜Jšœœœ˜Jšœœœ˜Jšœ œ˜šœœ=˜CJšœœ)œœ˜@—šœœ˜ šœœ ˜Jšœ˜Jšœœ™ Jšœ˜ —J˜JšœΟc ˜(Jšœ œ œ œ˜BJ˜J˜6J˜Jšœ˜Jšœ˜Jšœ˜J˜J˜Jšœ+˜+J˜J˜—šœœœ˜Jšœ ˜ Jšœ ˜ Jšœ œ)˜9Jšœ˜—J˜—JšœŸ˜J˜šžœœœ˜,Jšœ˜šœœœ˜0J˜J˜J˜Jšœ+˜+JšœI˜IJšœ5˜5Jšœ7˜7Jšœ3˜3šœ˜šœ˜Jšœœœ˜?—šœ˜Jšœœœ˜>—Jšœ˜—Jšœ*˜*J˜Jšœ˜Jšœ˜—Jšœ˜JšœŸ ˜J˜—šœ˜Jšœ˜šœœ ˜&šœ œœ˜Jšœ2œ˜K—šœ˜Jšœ'˜'J˜'—šœ˜J˜"—Jšœ˜Jšœ˜—Jšœ˜JšœŸ ˜J˜—šœ˜Jšœ˜š œœœœœœ˜*Jšœ œœœ˜*Jšœ(˜(Jšœ(˜(Jšœ2˜2Jšœ"˜"Jšœ˜Jšœ˜—Jšœ˜JšœŸ ˜J˜—šœ˜Jšœ˜š œœœœ˜Jšœ œœœ˜*Jšœ/˜/Jšœ˜Jšœ˜—Jšœ˜JšœŸ ˜J˜—šœ!˜!Jšœ˜š œœœœ˜Jšœ œœœ˜*Jšœ7˜7Jšœ9˜9Jšœ˜Jšœ˜—Jšœ˜JšœŸ˜J˜—šœ˜Jšœ˜š œœœœœœ˜&Jšœ œœœ˜*Jšœ4˜4Jšœœœœ˜>Jšœœœœ˜>Jšœ˜Jšœ˜—Jšœ˜JšœŸ ˜J˜—šœ˜Jšœ˜šœœ œœ˜7Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜—Jšœ˜JšœŸ ˜J˜—šœ˜Jšœ˜šœœ œœ˜4Jšœ˜Jšœ(˜(Jšœ&˜&Jšœ*˜*Jšœ/˜/Jšœ2˜2Jšœ˜Jšœ˜—Jšœ˜JšœŸ ˜J˜—š žœœœ$œœ˜WJšœ˜šœ9œœ˜NJ˜J˜J˜Jšœ ˜ Jšœ œ-˜@Jšœ˜Jšœ)˜)Jšœ,˜,Jšœ™J˜Jšœ˜Jšœ˜—Jšœ˜JšœŸ˜J˜—š ž œœœœœ˜IJšœ˜šœ˜Jšœ œ œœ˜B—šœ˜Jšœ œ œœ˜7—Jšœ9˜9šœ œ ˜7Jšœ8˜8Jšœ>˜>Jšœ˜—J˜/Jšœ œ$˜7Jšœ%˜)J˜.Jšœ˜JšœŸ ˜J˜—šžœœœ˜6Jšœ˜šœ&œœ˜:Jšœœ˜Jšœ˜—J˜JšœŸ ˜J˜—šž œœœ1˜NJšœ˜šœ&œœ˜:Jšœœœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜JšœŸ˜—J˜—Jšœ˜J˜šœœ˜ Jšœ-œ˜1——…—3ΌG