<> <> <> DIRECTORY Atom USING [GetPropFromList], Basics USING [BYTE, 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 [BYTE, 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.