<> <> <<>> DIRECTORY ClientStateInfo USING [defaultState, State, StateEqual], Convert USING [RopeFromCard], Imager USING [Context, DoSaveAll, MaskFillTrajectory, MaskStrokeTrajectory, MaskVector, ScaleT, SetColor, SetFont, SetStrokeEnd, SetStrokeJoint, SetStrokeWidth, SetXY, ShowRope, TranslateT, VEC], ImagerColor USING [ColorFromAtom], ImagerFont USING [Find, Font, Scale], ImagerPath USING [MoveTo, Trajectory], FS USING [GetDefaultWDir], IO USING [PutF, PutFR], Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc], MessageWindow USING [Append, Blink], Random USING [ChooseInt, Create], RatNums USING [RatNum, RatNumFromREAL], RCombiner USING [in, out], Real USING [Float], Rope USING [ROPE, Cat], RVHandleUtils USING [AddVertexToPolygon, AdjacencyHandle, AdjacencyHandleList, ClearVisitedFields, ConvexHull, ConvexPolygon, DumpVertexHandle, FindAdjacency, ImagerPolygonAndStateList, ImagerVecFromPoint, InitVertexHandle, PointList, PolygonExtractor, PreviousOutlineVertex, ReadIOVHLFromFile, ThreeOrMoreVertices, VertexHandle, vertexIndex, VertexVerifyIOVHLFromFile, VHandleFromIOVHL], SimpleCombiner USING [Combiner, Outline, OutlinesFromCombinerStructure], TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords], ViewerClasses USING [InitProc, NotifyProc, PaintProc, Viewer, ViewerClass, ViewerClassRec, ViewerRec], ViewerIO USING [CreateViewerStreams], ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass]; SimpleCombinerTester: CEDAR PROGRAM IMPORTS RatNums, RVHandleUtils, ClientStateInfo, RCombiner, SimpleCombiner, ViewerOps, Menus, MessageWindow, Imager, ImagerColor, ImagerFont, ImagerPath, TIPUser, Convert, IO, ViewerIO, Real, Random, Rope, FS SHARES Imager = BEGIN OPEN RN: RatNums, CSI: ClientStateInfo, RVHU: RVHandleUtils, RCB: RCombiner, SCB: SimpleCombiner; PlaneStructure: TYPE = RVHU.VertexHandle; CombinerStructure: TYPE = RVHU.VertexHandle; DOTWIDTH : INT = 10; -- diameter of vertices in edge drawing SEGMENTWIDTH: INT = 2; -- width of segment portion in edge drawing timesRomanBI: ImagerFont.Font ~ ImagerFont.Scale[ImagerFont.Find["xerox/pressfonts/timesroman-brr"], 10.]; --- why does scale of 10. work? CombinerViewer: TYPE = ViewerClasses.Viewer; CombinerViewerData: TYPE = REF CombinerViewerDataRec; CombinerViewerDataRec: TYPE = RECORD [ lowerStructure: PlaneStructure, -- for PlaneStructure = RVHU.VertexHandle, assumed to be a vertex on the (convex) outline of the structure. We try to follow the rule that only known valid structures are ever attached to a CombinerViewer, since the Paint proc will look here when the viewer is to be repainted. upperStructure: PlaneStructure, -- for PlaneStructure = RVHU.VertexHandle, assumed to be a vertex on the (convex) outline of the structure. We try to follow the rule that only known valid structures are ever attached to a CombinerViewer. x, y: REAL, -- specify starting location in viewer window for drawing a figure scale: REAL _ 1.0 -- current scale for Imager ]; PrivateState: TYPE = REF InclusionRelation; InclusionRelation: TYPE = { inside }; RenderPolygonList: PROC [context: Imager.Context, polygonList: RVHU.ImagerPolygonAndStateList, insideColor: ATOM] ~ { WHILE polygonList # NIL DO state: REF InclusionRelation _ NARROW[polygonList.first.state]; polygon: ImagerPath.Trajectory _ polygonList.first.trajectory; IF state = NIL THEN context.SetColor[ImagerColor.ColorFromAtom[$White]] ELSE IF state^ = inside THEN context.SetColor[ImagerColor.ColorFromAtom[insideColor]] ELSE context.SetColor[ImagerColor.ColorFromAtom[$White]]; context.MaskFillTrajectory[ polygon ]; polygonList _ polygonList.rest; ENDLOOP; }; DrawPlaneStructure: PUBLIC PROC[context: Imager.Context, v: PlaneStructure, showState: BOOL _ TRUE, showVerticesOnly: BOOL _ FALSE, labelVertices: BOOL _ TRUE ] = { <> visitedValue: BOOL; IF v = NIL THEN RETURN; -- no vertices Imager.SetStrokeEnd[context, round]; Imager.SetFont[context, timesRomanBI]; IF v.adjacentVertices = NIL THEN { -- one vertex p1: Imager.VEC _ RVHU.ImagerVecFromPoint[v.coordinates]; Imager.SetStrokeWidth[context, DOTWIDTH]; Imager.MaskStrokeTrajectory[context, ImagerPath.MoveTo[ p1 ] ]; IF labelVertices THEN { context.SetXY[[p1.x, p1.y + 7.]]; context.ShowRope[Convert.RopeFromCard[v.index]]; }; } ELSE { -- two or more vertices visitedValue _ v.visited; DrawPlaneStructureSubr[context, v, showState, showVerticesOnly, labelVertices, NOT visitedValue]; -- toggle visitedValue }; }; DrawPlaneStructureSubr: PROC[context: Imager.Context, v: PlaneStructure, showState: BOOL, showVerticesOnly: BOOL, labelVertices: BOOL, visitedValue: BOOL] = { <> vAdjList: RVHU.AdjacencyHandleList _ v.adjacentVertices; lastVertex, nextVertex: PlaneStructure; done: BOOL; vToNext, NextTov: RVHU.AdjacencyHandle; <> v.visited _ visitedValue; -- record that we've visited this vertex <> lastVertex _ vAdjList.first.vertex; vAdjList _ vAdjList.rest; -- shift past marker vertex (i.e. first iteration of loop begins after it) done _ FALSE; WHILE NOT done DO nextVertex _ vAdjList.first.vertex; IF nextVertex = lastVertex THEN done _ TRUE; -- test for last vertex to be processed IF (nextVertex.visited # visitedValue) THEN DrawPlaneStructureSubr[ context, nextVertex, showState, showVerticesOnly, labelVertices, visitedValue ] ELSE { [ vToNext, NextTov ] _ RVHU.FindAdjacency[ v, nextVertex ]; IF NOT showState OR NOT CSI.StateEqual[vToNext.leftState, NextTov.leftState] THEN { p1: Imager.VEC _ RVHU.ImagerVecFromPoint[v.coordinates]; p2: Imager.VEC _ RVHU.ImagerVecFromPoint[nextVertex.coordinates]; trajectory: ImagerPath.Trajectory _ ImagerPath.MoveTo[p1]; Imager.SetStrokeWidth[context, DOTWIDTH]; Imager.MaskStrokeTrajectory[context, trajectory]; IF labelVertices THEN { context.SetXY[[p1.x, p1.y + 7.]]; context.ShowRope[Convert.RopeFromCard[v.index]]; }; IF NOT showVerticesOnly THEN { Imager.SetStrokeWidth[context, SEGMENTWIDTH]; Imager.MaskVector [context, p1, p2 ]; -- Draw [v, nextVertex] }; trajectory _ ImagerPath.MoveTo[p2]; Imager.SetStrokeWidth[context, DOTWIDTH]; Imager.MaskStrokeTrajectory[context, trajectory]; IF labelVertices THEN { context.SetXY[[p2.x, p2.y + 7.]]; context.ShowRope[Convert.RopeFromCard[nextVertex.index]]; }; }; }; vAdjList _ vAdjList.rest; ENDLOOP; }; <<>> UpperPolygonStart: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; saveVertexIndex _ RVHU.vertexIndex; upperStructureOpen _ TRUE; MessageWindow.Append[ message : "Enter your polygon", clearFirst: TRUE]; }; UpperPolygonDone: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; upperStructureprev: PlaneStructure; outline: BOOL _ TRUE; IF (NOT upperStructureOpen) THEN { MessageWindow.Append[ message : "No upperStructure is open now", clearFirst: TRUE]; MessageWindow.Blink; RETURN; }; IF NOT RVHU.ThreeOrMoreVertices[upperStructure] THEN { MessageWindow.Append[ message : "Input upperStructure has fewer than three vertices; reenter", clearFirst: TRUE]; MessageWindow.Blink; upperStructure _ RVHU.InitVertexHandle[]; RVHU.vertexIndex _ saveVertexIndex; upperStructureOpen _ FALSE; RETURN; }; <> upperStructureprev _ RVHU.PreviousOutlineVertex[upperStructure]; IF NOT RVHU.ConvexPolygon[upperStructureprev, upperStructure, outline] THEN { MessageWindow.Append[ message : "Input upperStructure is not convex; reenter", clearFirst: TRUE]; MessageWindow.Blink; upperStructure _ RVHU.InitVertexHandle[]; RVHU.vertexIndex _ saveVertexIndex; upperStructureOpen _ FALSE; }; upperStructureOpen _ FALSE; }; Union: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; v: CombinerStructure; L: RVHU.ImagerPolygonAndStateList; IF upperStructureOpen THEN { MessageWindow.Append[ message : "You have an open input polygon", clearFirst: TRUE]; MessageWindow.Blink; RETURN; }; RVHU.DumpVertexHandle[ lowerStructure, Rope.Cat[FS.GetDefaultWDir[],"LowerPlaneStructure"]]; RVHU.DumpVertexHandle[ upperStructure, Rope.Cat[FS.GetDefaultWDir[],"UpperPlaneStructure"]]; v _ RVHU.PreviousOutlineVertex[upperStructure]; L _ RVHU.PolygonExtractor[ v, upperStructure ]; RVHU.ClearVisitedFields[v, upperStructure]; lowerStructure _ SCB.Combiner[L.first.trajectory, Union, lowerStructure]; upperStructure _ RVHU.InitVertexHandle[]; selfData.lowerStructure _ lowerStructure; --update Viewer data fields (InitViewer actions) selfData.upperStructure _ upperStructure; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; Difference: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; v: CombinerStructure; L: RVHU.ImagerPolygonAndStateList; IF upperStructureOpen THEN { MessageWindow.Append[ message : "You have an open input polygon", clearFirst: TRUE]; MessageWindow.Blink; RETURN; }; RVHU.DumpVertexHandle[ lowerStructure, Rope.Cat[FS.GetDefaultWDir[],"LowerPlaneStructure"]]; RVHU.DumpVertexHandle[ upperStructure, Rope.Cat[FS.GetDefaultWDir[],"UpperPlaneStructure"]]; v _ RVHU.PreviousOutlineVertex[upperStructure]; L _ RVHU.PolygonExtractor[ v, upperStructure ]; RVHU.ClearVisitedFields[v, upperStructure]; lowerStructure _ SCB.Combiner[L.first.trajectory, Difference, lowerStructure]; upperStructure _ RVHU.InitVertexHandle[]; selfData.lowerStructure _ lowerStructure; --update Viewer data fields (InitViewer actions) selfData.upperStructure _ upperStructure; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; Outlines: Menus.MenuProc ~ { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; globalOutlineList _ SCB.OutlinesFromCombinerStructure[lowerStructure]; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: $Outlines, clearClient: TRUE]; }; DumpBothPlaneStructures: Menus.MenuProc = { IF lowerStructure = NIL OR upperStructure = NIL THEN { MessageWindow.Append[ message : "You don't have a lowerStructure and a upperStructure polygon", clearFirst: TRUE]; MessageWindow.Blink; RETURN; }; RVHU.DumpVertexHandle[ lowerStructure, Rope.Cat[FS.GetDefaultWDir[],"LowerPlaneStructure"]]; RVHU.DumpVertexHandle[ upperStructure, Rope.Cat[FS.GetDefaultWDir[],"UpperPlaneStructure"]]; }; ReadBothPlaneStructures: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; numberVertices: CARDINAL; maxVertexIndex: CARDINAL _ 0; RCB.out.PutF["\n\nVerify lowerStructure argument"]; maxVertexIndex _ RVHU.VertexVerifyIOVHLFromFile[Rope.Cat[FS.GetDefaultWDir[],"LowerPlaneStructure"], RCB.out]; [lowerStructure, numberVertices ] _ RVHU.VHandleFromIOVHL[ RVHU.ReadIOVHLFromFile[Rope.Cat[FS.GetDefaultWDir[],"LowerPlaneStructure"], RCB.out] ]; RVHU.vertexIndex _ MAX[maxVertexIndex, numberVertices]; -- don't repeat indices RCB.out.PutF["\n\nVerify upperStructure argument"]; maxVertexIndex _ RVHU.VertexVerifyIOVHLFromFile[Rope.Cat[FS.GetDefaultWDir[],"UpperPlaneStructure"], RCB.out]; RCB.out.PutF["\n"]; [upperStructure, numberVertices ] _ RVHU.VHandleFromIOVHL[ RVHU.ReadIOVHLFromFile[Rope.Cat[FS.GetDefaultWDir[],"UpperPlaneStructure"], RCB.out] ]; RVHU.vertexIndex _ MAX[ RVHU.vertexIndex + numberVertices, maxVertexIndex]; RVHU.vertexIndex _ RVHU.vertexIndex + 1; -- set next vertex to be allocated selfData.lowerStructure _ lowerStructure; -- InitViewer actions selfData.upperStructure _ upperStructure; upperStructureOpen _ FALSE; -- Override other input action in progress ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; DumpLowerPlaneStructure: Menus.MenuProc = { RVHU.DumpVertexHandle[ lowerStructure, Rope.Cat[FS.GetDefaultWDir[],"LowerPlaneStructure"]]; }; ReadLowerPlaneStructure: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; numberVertices: CARDINAL; maxVertexIndex: CARDINAL _ 0; RCB.out.PutF["\n\nVerify lowerStructure argument"]; maxVertexIndex _ RVHU.VertexVerifyIOVHLFromFile[Rope.Cat[FS.GetDefaultWDir[],"LowerPlaneStructure"], RCB.out]; [lowerStructure, numberVertices ] _ RVHU.VHandleFromIOVHL[ RVHU.ReadIOVHLFromFile[Rope.Cat[FS.GetDefaultWDir[],"LowerPlaneStructure"], RCB.out] ]; RVHU.vertexIndex _ MAX[maxVertexIndex, numberVertices]; -- don't repeat indices RVHU.vertexIndex _ RVHU.vertexIndex + 1; -- next index to be assigned to a vertex selfData.lowerStructure _ lowerStructure; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; Reset: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; globalState _ CSI.defaultState; globalOutlineList _ NIL; lowerStructure _ RVHU.InitVertexHandle[]; RVHU.vertexIndex _ 1; upperStructure _ RVHU.InitVertexHandle[]; upperStructureOpen _ FALSE; selfData.lowerStructure _ RVHU.InitVertexHandle[]; -- repeat InitViewer actions selfData.upperStructure _ RVHU.InitVertexHandle[]; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; StateGeometry: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: $StateGeometry, clearClient: TRUE]; }; EdgesVertices: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: $EdgesVertices, clearClient: TRUE]; }; VertexLabels: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: $VertexLabels, clearClient: TRUE]; }; PlaneStructureDraw: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; fillDraw _ FALSE; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; FillDraw: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; fillDraw _ TRUE; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; Zoom: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; IF mouseButton=red THEN { selfData.scale _ selfData.scale*2; selfData.x _ selfData.x - (1.0 / selfData.scale) * 300.0; selfData.y _ selfData.y - (1.0 / selfData.scale) * 350.0 } ELSE { selfData.x _ selfData.x + (1.0 / selfData.scale) * 300.0; selfData.y _ selfData.y + (1.0 / selfData.scale) * 350.0; selfData.scale _ selfData.scale/2 }; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; Horizontal: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; IF mouseButton=red THEN selfData.x _ selfData.x - (1.0 / selfData.scale) * 100.0 ELSE selfData.x _ selfData.x + (1.0 / selfData.scale) * 100.0; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; Vertical: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; IF mouseButton=red THEN selfData.y _ selfData.y + (1.0 / selfData.scale) * 100.0 ELSE selfData.y _ selfData.y - (1.0 / selfData.scale) * 100.0; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; DoConvexHull: Menus.MenuProc ~ { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; M: RVHU.PointList; x, y: REAL; xRat, yRat: RN.RatNum; state: CSI.State; <> globalPointList: RVHU.PointList _ NIL; globalPointListEnd: RVHU.PointList _ NIL; numGlobalPoints: CARDINAL _ 10; FOR I: CARDINAL IN [1..numGlobalPoints] DO x _ Real.Float [Random.ChooseInt[min:1, max:600]]; y _ Real.Float [Random.ChooseInt[min:1, max:400]]; xRat _ RN.RatNumFromREAL[(1.0 / selfData.scale) * x - selfData.x]; yRat _ RN.RatNumFromREAL[ (1.0 / selfData.scale) * y - selfData.y]; IF globalPointList = NIL THEN globalPointList _ globalPointListEnd _ CONS[ [xRat, yRat], NIL] ELSE { globalPointListEnd.rest _ CONS[ [xRat,yRat], NIL]; globalPointListEnd _ globalPointListEnd.rest; }; ENDLOOP; M _ RVHU.ConvexHull[globalPointList]; upperStructure _ NIL; state _ NEW[InclusionRelation _ inside ]; WHILE M#NIL DO upperStructure _ RVHU.AddVertexToPolygon [upperStructure, M.first.x, M.first.y, state ]; M _ M.rest; ENDLOOP; selfData.upperStructure _ upperStructure; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; InitViewer: ViewerClasses.InitProc -- [self: ViewerClasses.Viewer] -- = { size: REAL = 100.0; self.data _ NEW[CombinerViewerDataRec _ [ lowerStructure: RVHU.InitVertexHandle[], upperStructure: RVHU.InitVertexHandle[], x: 0.0, y: 0.0 ]]; self.name _ "CombinerViewer"; }; Notify: ViewerClasses.NotifyProc -- [self:ViewerClasses.Viewer,input:LIST OF REF ANY] -- ={ xy: TIPUser.TIPScreenCoords _ NARROW[input.first]; x, y: RN.RatNum; clearVal: BOOL _ TRUE; selfData: CombinerViewerData _ NARROW[self.data]; x _ RN.RatNumFromREAL[(1.0 / selfData.scale) * xy.mouseX - selfData.x]; y _ RN.RatNumFromREAL[ (1.0 / selfData.scale) * xy.mouseY - selfData.y]; SELECT input.rest.first FROM $RedRelease => { IF upperStructureOpen THEN { upperStructure _ RVHU.AddVertexToPolygon [upperStructure, x, y, globalState ]; selfData.upperStructure _ upperStructure; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; }; $YellowRelease => { }; $BlueRelease => { }; ENDCASE => ERROR; }; Paint: ViewerClasses.PaintProc = { <<[self: Viewer, context: Imager.Context, whatChanged: REF, clear: BOOL]>> <> RenderPolygons: PROC ~ { v, w: PlaneStructure; <> <> <> context.ScaleT[selfData.scale]; context.TranslateT[[selfData.x, selfData.y]]; w _ selfData.lowerStructure; IF NOT RVHU.ThreeOrMoreVertices[w] THEN { context.SetColor[ImagerColor.ColorFromAtom[$Black]]; DrawPlaneStructure[context: context, v: w, showState: FALSE, showVerticesOnly: FALSE, labelVertices: FALSE] } ELSE { v _ RVHU.PreviousOutlineVertex[w]; RenderPolygonList[context, RVHU.PolygonExtractor[ v, w ], $Red ]; RVHU.ClearVisitedFields[v, w]; }; w _ selfData.upperStructure; IF NOT RVHU.ThreeOrMoreVertices[w] THEN { context.SetColor[ImagerColor.ColorFromAtom[$Black]]; DrawPlaneStructure[context: context, v: w, showState: FALSE, showVerticesOnly: FALSE, labelVertices: FALSE] } ELSE { v _ RVHU.PreviousOutlineVertex[w]; RenderPolygonList[context, RVHU.PolygonExtractor[ v, w ], $Green ]; RVHU.ClearVisitedFields[v, w]; }; }; DrawViewerPlaneStructures: PROC ~ { <> <> context.ScaleT[selfData.scale]; context.TranslateT[[selfData.x, selfData.y]]; context.SetColor[ImagerColor.ColorFromAtom[$Red]]; DrawPlaneStructure[context: context, v: selfData.lowerStructure, showState: showState, showVerticesOnly: showVerticesOnly, labelVertices: labelVertices]; context.SetColor[ImagerColor.ColorFromAtom[$Green]]; DrawPlaneStructure[context: context, v: selfData.upperStructure, showState: showState, showVerticesOnly: showVerticesOnly, labelVertices: labelVertices]; }; DrawOutlines: PROC ~ { L: LIST OF SCB.Outline _ globalOutlineList; context.ScaleT[selfData.scale]; context.TranslateT[[selfData.x, selfData.y]]; context.SetColor[ImagerColor.ColorFromAtom[$Blue]]; context.SetStrokeEnd[round]; context.SetStrokeJoint[round]; context.SetStrokeWidth[SEGMENTWIDTH]; WHILE L#NIL DO context.MaskStrokeTrajectory[L.first]; L _ L.rest; ENDLOOP; }; selfData: CombinerViewerData _ NARROW[self.data]; <> SELECT whatChanged FROM $PlaneStructureDraw => { context.DoSaveAll[DrawViewerPlaneStructures]; }; NIL => { IF fillDraw THEN context.DoSaveAll[RenderPolygons] ELSE context.DoSaveAll[DrawViewerPlaneStructures]; }; $StateGeometry => { showState _ NOT showState; context.DoSaveAll[DrawViewerPlaneStructures]; }; $EdgesVertices => { showVerticesOnly _ NOT showVerticesOnly; context.DoSaveAll[DrawViewerPlaneStructures]; }; $VertexLabels => { labelVertices _ NOT labelVertices; context.DoSaveAll[DrawViewerPlaneStructures]; }; $Outlines => { context.DoSaveAll[DrawOutlines]; }; ENDCASE => ERROR; }; RegisterCombinerViewerClass: PROC ~ { menu: Menus.Menu _ Menus.CreateMenu[3]; combinerViewerClass: ViewerClasses.ViewerClass; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Reset", proc: Reset], line:0]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"DumpLower ", proc: DumpLowerPlaneStructure], line:0]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"LoadLower ", proc: ReadLowerPlaneStructure], line:0]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"DumpBoth ", proc: DumpBothPlaneStructures], line:0]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"LoadBoth ", proc: ReadBothPlaneStructures], line:0]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"UppStart ", proc: UpperPolygonStart], line:1]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"UppDone ", proc: UpperPolygonDone], line:1]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"RandHull", proc: DoConvexHull], line:1]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Union ", proc: Union], line:1]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Difference ", proc: Difference], line:1]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Outlines ", proc: Outlines], line:1]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"StateGeometry ", proc: StateGeometry], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"EdgesVertices ", proc: EdgesVertices], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"VertexLabels ", proc: VertexLabels], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"PlaneStructDraw ", proc: PlaneStructureDraw], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"FillDraw ", proc: FillDraw], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Zoom ", proc: Zoom], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Horizontal ", proc: Horizontal], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Vertical ", proc: Vertical], line:2]; combinerViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ flavor: $CombinerViewer, init: InitViewer, notify: Notify, tipTable: TIPUser.InstantiateNewTIPTable["Combiner.tip"], paint: Paint, menu: menu ]]; ViewerOps.RegisterViewerClass[flavor: $CombinerViewer, class: combinerViewerClass]; }; <<**** Top level variables>> <<>> <> logTitle: Rope.ROPE; <> globalState: CSI.State; globalOutlineList: LIST OF SCB.Outline; <<(Lower and Upper) Structure display options>> showState: BOOL _ TRUE; -- global variables for control of PlaneStructure display format showVerticesOnly: BOOL _ FALSE; labelVertices: BOOL _ TRUE; fillDraw: BOOL _ TRUE; <> lowerStructure: PlaneStructure; -- The convention is that if the lower structure exists, then lowerStructure is one of its outline vertices (remark: lowerStructures cannot be read in). <> upperStructure: PlaneStructure; -- The convention is that if the upper structure exists, then upperStructure is one of its outline vertices upperStructureOpen: BOOLEAN; -- true when an upperStructure (which currently must be a polygon) is being read in saveVertexIndex: INT; -- for backup if unacceptable upperStructure read <<>> <<**** End of Top level variables>> <<>> RegisterCombinerViewerClass[]; <> globalState _ CSI.defaultState; globalOutlineList _ NIL; lowerStructure _ RVHU.InitVertexHandle[]; RVHU.vertexIndex _ 1; upperStructure _ RVHU.InitVertexHandle[]; upperStructureOpen _ FALSE; [] _ ViewerOps.CreateViewer[flavor: $CombinerViewer, info: [iconic:FALSE, column: color] ]; <> <<>> <> logTitle _ IO.PutFR["Combiner Log"]; [RCB.in, RCB.out] _ ViewerIO.CreateViewerStreams[logTitle]; <> [] _ Random.Create[range: 0, seed: -1]; END. <<>>