<> <> <> <<>> DIRECTORY RatNums, EuclideanGraphs, ConvexEuclideanGraphs, ConvexCombiner, CombinePoly, ViewerClasses, ViewerOps, MessageWindow, Rope, Menus, Imager, ImagerColor, ImagerFont , ImagerPath, ImagerInterpress, TIPUser, Convert, IO, ViewerIO, Real, Random; CombinePolyTester: CEDAR PROGRAM IMPORTS RatNums, EuclideanGraphs, ConvexEuclideanGraphs, ConvexCombiner, CombinePoly, ViewerOps, Menus, MessageWindow, Rope, Imager, ImagerColor, ImagerFont, ImagerPath, ImagerInterpress, TIPUser, Convert, IO, Real, Random SHARES Imager = BEGIN OPEN RN: RatNums, EG: EuclideanGraphs, CEG: ConvexEuclideanGraphs, CC: ConvexCombiner, CP: CombinePoly; DOTWIDTH : INT = 10; -- diameter of vertices in edge drawing SEGMENTWIDTH: INT = 2; -- width of segment portion in edge drawing timesRomanBI: Imager.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 [ lowerGraphEnd: CP.DBID, -- for CEG.ConvexEuclideanGraph = EG.Vertex, 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. upperGraphEnd: CP.PolyID, -- for CEG.ConvexEuclideanGraph = EG.Vertex, 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. lowerGraphRegions: CP.RegionGenerator, x, y: REAL, -- specify starting location in viewer window for drawing a figure scale: REAL _ 1.0 -- current scale for Imager ]; Verbosity: TYPE = CEG.Verbosity; UpperPolygonStart: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; saveVertexIndex _ EG.vertexIndex; upperGraphOpen _ TRUE; pointCount _ 0; MessageWindow.Append[ message : "Enter your polygon", clearFirst: TRUE]; }; UpperPolygonDone: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; upperGraphprev: CEG.ConvexEuclideanGraph; outline: BOOL _ TRUE; IF (NOT upperGraphOpen) THEN { MessageWindow.Append[ message : "No upperGraphEnd is open now", clearFirst: TRUE]; MessageWindow.Blink; RETURN; }; IF NOT CEG.ThreeOrMoreVertices[upperGraphEnd] THEN { MessageWindow.Append[ message : "Input upperGraphEnd has fewer than three vertices; reenter", clearFirst: TRUE]; MessageWindow.Blink; upperGraphEnd _ NIL; EG.vertexIndex _ saveVertexIndex; upperGraphOpen _ FALSE; RETURN; }; <> upperGraphprev _ CEG.SpecialPreviousOutlineVertex[upperGraphEnd]; IF NOT CEG.ConvexPolygon[upperGraphprev, upperGraphEnd, outline] THEN { MessageWindow.Append[ message : "Input upperGraphEnd is not convex; reenter", clearFirst: TRUE]; MessageWindow.Blink; upperGraphEnd _ NIL; EG.vertexIndex _ saveVertexIndex; upperGraphOpen _ FALSE; }; upperGraphOpen _ FALSE; }; SetUpperPolygonClientData: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; IF NOT CEG.ThreeOrMoreVertices[upperGraphEnd] THEN { MessageWindow.Append[ message : "Current upperGraphEnd has fewer than three vertices", clearFirst: TRUE]; MessageWindow.Blink; RETURN; }; upperGraphStart _ CEG.SpecialPreviousOutlineVertex[upperGraphEnd]; CEG.SetPolygonClientData[upperGraphStart, upperGraphEnd, globalClientData]; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; RunCombiner: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; IF upperGraphOpen THEN { MessageWindow.Append[ message : "You have an open upperGraphEnd", clearFirst: TRUE]; MessageWindow.Blink; RETURN; }; CEG.DumpGraph[ lowerGraphEnd, ropeFromClientData, "///Users/Arnon.pa/Combiner/LowerGraph"]; CEG.DumpGraph[ upperGraphEnd, ropeFromClientData, "///Users/Arnon.pa/Combiner/UpperGraph"]; upperGraphStart _ CEG.SpecialPreviousOutlineVertex[upperGraphEnd]; lowerGraphEnd _ CP.PolygonIntoDatabase[upperGraphEnd, lowerGraphEnd, clientDataCombiner, clientDataEqual ]; upperGraphEnd _ NIL; selfData.lowerGraphEnd _ lowerGraphEnd; --update Viewer data fields (InitViewer actions) selfData.upperGraphEnd _ upperGraphEnd; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; RunCleaner: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; CC.SimpleCleaner[lowerGraphEnd, clientDataEqual, verbosity]; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; GetLowerRegions: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; IF NOT CEG.ThreeOrMoreVertices[lowerGraphEnd] THEN { MessageWindow.Append[ message : "lowerGraphEnd has fewer than three vertices; can't do regions yet", clearFirst: TRUE]; MessageWindow.Blink; RETURN; }; lowerGraphRegions _ CP.MaximalRegions[lowerGraphEnd, isA]; selfData.lowerGraphRegions _ lowerGraphRegions; -- InitViewer actions showGraphs _ FALSE; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; DumpBothGraphs: Menus.MenuProc = { IF lowerGraphEnd = NIL OR upperGraphEnd = NIL THEN { MessageWindow.Append[ message : "You don't have a lowerGraphEnd and a upperGraphEnd polygon", clearFirst: TRUE]; MessageWindow.Blink; RETURN; }; CEG.DumpGraph[ lowerGraphEnd, ropeFromClientData, "///Users/Arnon.pa/Combiner/LowerGraph"]; CEG.DumpGraph[ upperGraphEnd, ropeFromClientData, "///Users/Arnon.pa/Combiner/UpperGraph"]; }; ReadBothGraphs: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; numberVertices: CARDINAL; maxVertexIndex: CARDINAL _ 0; <> <> [lowerGraphEnd, numberVertices ] _ CEG.GraphFromFile["///Users/Arnon.pa/Combiner/LowerGraph", clientDataFromRope, out]; EG.vertexIndex _ MAX[maxVertexIndex, numberVertices]; -- don't repeat indices <> <> <> [upperGraphEnd, numberVertices ] _ CEG.GraphFromFile["///Users/Arnon.pa/Combiner/UpperGraph", clientDataFromRope, out]; EG.vertexIndex _ MAX[ EG.vertexIndex + numberVertices, maxVertexIndex]; EG.vertexIndex _ EG.vertexIndex + 1; -- set next vertex to be allocated selfData.lowerGraphEnd _ lowerGraphEnd; -- InitViewer actions selfData.upperGraphEnd _ upperGraphEnd; upperGraphOpen _ FALSE; -- Override other input action in progress ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; DumpLowerGraph: Menus.MenuProc = { CEG.DumpGraph[ lowerGraphEnd, ropeFromClientData, "///Users/Arnon.pa/Combiner/LowerGraph"]; }; ReadLowerGraph: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; numberVertices: CARDINAL; maxVertexIndex: CARDINAL _ 0; <> <> [lowerGraphEnd, numberVertices ] _ CEG.GraphFromFile["///Users/Arnon.pa/Combiner/LowerGraph", clientDataFromRope, out]; EG.vertexIndex _ MAX[maxVertexIndex, numberVertices]; -- don't repeat indices EG.vertexIndex _ EG.vertexIndex + 1; -- next index to be assigned to a vertex selfData.lowerGraphEnd _ lowerGraphEnd; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; Reset: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; globalClientData _ NIL; lowerGraphEnd _ CP.CreateDatabase[]; lowerGraphRegions _ NIL; upperGraphStart _ upperGraphEnd _ CP.CreateDatabase[]; upperGraphOpen _ FALSE; selfData.lowerGraphEnd _ lowerGraphEnd; -- repeat InitViewer actions selfData.upperGraphEnd _ upperGraphEnd; selfData.lowerGraphRegions _ lowerGraphRegions; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; StateGeometry: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; showClientData _ NOT showClientData; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; <> <> <> <> <> <<};>> <<>> <> <> <> <> <<};>> <<>> FillNoFill: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; fillDraw _ NOT fillDraw; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; GraphsRegions: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; showGraphs _ NOT showGraphs; 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]; }; StepGlobalState: Menus.MenuProc = { color: Color _ NARROW[globalClientData]; newrgb: ImagerColor.RGB; IF mouseButton=red THEN { newrgb.R _ color.R - 0.1; IF newrgb.R <= 0.0 THEN newrgb.R _ 1.0; newrgb.G _ color.G; newrgb.B _ color.B; } ELSE IF mouseButton=yellow THEN { newrgb.G _ color.G - 0.1; IF newrgb.G <= 0.0 THEN newrgb.G _ 1.0; newrgb.R _ color.R; newrgb.B _ color.B; } ELSE IF mouseButton=blue THEN { newrgb.B _ color.B - 0.1; IF newrgb.B <= 0.0 THEN newrgb.B _ 1.0; newrgb.R _ color.R; newrgb.G _ color.G; } ELSE ERROR; globalClientData _ NEW[ImagerColor.RGB _ [R: newrgb.R, G: newrgb.G, B: newrgb.B ] ]; <> <> }; GlobalStateRed: Menus.MenuProc = { globalClientData _ NEW[ImagerColor.RGB _ [R: 1.0, G: 0.0, B: 0.0 ] ]; }; GlobalStateGreen: Menus.MenuProc = { globalClientData _ NEW[ImagerColor.RGB _ [R: 0.0, G: 1.0, B: 0.0 ] ]; }; GlobalStateBlue: Menus.MenuProc = { globalClientData _ NEW[ImagerColor.RGB _ [R: 0.0, G: 0.0, B: 1.0 ] ]; }; GlobalStateWhite: Menus.MenuProc = { globalClientData _ NEW[ImagerColor.RGB _ [R: 1.0, G: 1.0, B: 1.0 ] ]; }; GlobalStateBlack: Menus.MenuProc = { globalClientData _ NEW[ImagerColor.RGB _ [R: 0.0, G: 0.0, B: 0.0 ] ]; }; RandomTest: Menus.MenuProc = { DO DoConvexHull[parent]; RunCombiner[parent]; RunCleaner[parent]; ENDLOOP; }; DoConvexHull: Menus.MenuProc ~ { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; L, LEnd, M: EG.PointList; x, y: REAL; xRat, yRat: RN.RatNum; myClientData: REF; <> L _ NIL; FOR I: CARDINAL IN [1..20] 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 L = NIL THEN L _ LEnd _ CONS[ [xRat, yRat], NIL] ELSE { LEnd.rest _ CONS[ [xRat,yRat], NIL]; LEnd _ LEnd.rest; }; ENDLOOP; M _ CEG.ConvexHull[L]; upperGraphStart _ upperGraphEnd _ NIL; myClientData _ NEW[ImagerColor.RGB _ [R: Real.Float [Random.ChooseInt[min:1, max:100]] / 100., G: Real.Float [Random.ChooseInt[min:1, max:100]] / 100., B: Real.Float [Random.ChooseInt[min:1, max:100]] / 100. ] ]; WHILE M#NIL DO [upperGraphStart, upperGraphEnd] _ CEG.AddVertexToPolygon[upperGraphStart, upperGraphEnd, EG.MakePointFromRatNums[M.first.x, M.first.y], myClientData]; M _ M.rest; ENDLOOP; selfData.upperGraphEnd _ upperGraphEnd; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; TrajectoryFromPointGenerator: PROC [pointGen: CP.PointGenerator] RETURNS [traj: ImagerPath.Trajectory] ~ { pointAndDone: CP.PointAndDone _ CP.NextPoint[pointGen]; point, firstPoint: CP.Point _ pointAndDone.point; vec: Imager.VEC _ [point.x, point.y ]; IF pointAndDone.done THEN RETURN[NIL]; traj _ ImagerPath.MoveTo[vec]; pointAndDone _ CP.NextPoint[pointGen]; WHILE NOT pointAndDone.done DO point _ pointAndDone.point; vec _ [point.x, point.y ]; traj _ traj.LineTo[vec]; pointAndDone _ CP.NextPoint[pointGen]; ENDLOOP; vec _ [firstPoint.x, firstPoint.y ]; -- edge from last to first vertex traj _ traj.LineTo[vec]; }; FillDrawRegionGenerator: PROC [context: Imager.Context, regions: CP.RegionGenerator] ~ { region: CP.OutlineHolesDataAndDone _ CP.NextRegion[regions]; WHILE NOT region.done DO color: Color _ NARROW[region.data]; regionOutline: Imager.Trajectory _ TrajectoryFromPointGenerator[region.outline]; IF color # NIL THEN context.SetColor[ImagerColor.ColorFromRGB[color^]] ELSE context.SetColor[ImagerColor.ColorFromRGB[[0.0, 0.0, 0.0]]]; -- black for NIL context.MaskFillTrajectory[regionOutline]; IF region.holes#NIL THEN FillDrawRegionGenerator[context, region.holes]; -- recursively draw holes region _ CP.NextRegion[regions]; ENDLOOP; }; LineDrawRegionGenerator: PROC [context: Imager.Context, regions: CP.RegionGenerator] ~ { region: CP.OutlineHolesDataAndDone _ CP.NextRegion[regions]; Imager.SetStrokeEnd[context, round]; Imager.SetStrokeWidth[context, SEGMENTWIDTH]; WHILE NOT region.done DO regionOutline: Imager.Trajectory _ TrajectoryFromPointGenerator[region.outline]; context.MaskStrokeTrajectory[regionOutline]; IF region.holes#NIL THEN LineDrawRegionGenerator[context, region.holes]; -- recursively draw holes region _ CP.NextRegion[regions]; ENDLOOP; }; FillDrawRegionList: PROC [context: Imager.Context, regions: CEG.RegionList] ~ { WHILE regions # NIL DO region: CEG.Region _ regions.first; color: Color _ NARROW[region.clientData]; regionOutline: Imager.Trajectory _ region.outline; IF color # NIL THEN context.SetColor[ImagerColor.ColorFromRGB[color^]] ELSE context.SetColor[ImagerColor.ColorFromRGB[[0.0, 0.0, 0.0]]]; -- black for NIL context.MaskFillTrajectory[regionOutline]; IF region.holes#NIL THEN FillDrawRegionList[context, region.holes]; -- recursively draw holes regions _ regions.rest; ENDLOOP; }; LineDrawRegionList: PROC [context: Imager.Context, regions: CEG.RegionList] ~ { Imager.SetStrokeEnd[context, round]; Imager.SetStrokeWidth[context, SEGMENTWIDTH]; WHILE regions # NIL DO region: CEG.Region _ regions.first; regionOutline: Imager.Trajectory _ region.outline; context.MaskStrokeTrajectory[regionOutline]; IF region.holes#NIL THEN LineDrawRegionList[context, region.holes]; -- recursively draw holes regions _ regions.rest; ENDLOOP; }; LineDrawGraph: PUBLIC PROC[context: Imager.Context, v: CEG.ConvexEuclideanGraph, showClientData: 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 _ EG.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; LineDrawGraphSubr[context, v, showClientData, showVerticesOnly, labelVertices, NOT visitedValue]; -- toggle visitedValue }; }; LineDrawGraphSubr: PROC[context: Imager.Context, v: CEG.ConvexEuclideanGraph, showClientData: BOOL, showVerticesOnly: BOOL, labelVertices: BOOL, visitedValue: BOOL] = { <> vAdjList: EG.AdjacencyList _ v.adjacentVertices; lastVertex, nextVertex: CEG.ConvexEuclideanGraph; done: BOOL; vToNext, NextTov: EG.Adjacency; <> 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 LineDrawGraphSubr[ context, nextVertex, showClientData, showVerticesOnly, labelVertices, visitedValue ] ELSE { [vToNext, NextTov] _ EG.FindAdjacency[ v, nextVertex ]; IF NOT showClientData OR NOT clientDataEqual[CEG.GetEdgeClientData[vToNext], CEG.GetEdgeClientData[NextTov] ] THEN { p1: Imager.VEC _ EG.ImagerVecFromPoint[v.coordinates]; p2: Imager.VEC _ EG.ImagerVecFromPoint[nextVertex.coordinates]; trajectory: Imager.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; }; <<>> ObjectsToInterpress: Menus.MenuProc = { self: CombinerViewer _ NARROW[parent, ViewerClasses.Viewer]; selfData: CombinerViewerData _ NARROW[self.data]; action: PROC [context: Imager.Context] = { v, w: CEG.ConvexEuclideanGraph; Imager.ScaleT[context, Imager.metersPerPoint]; Imager.SetPriorityImportant[context, TRUE]; context.ScaleT[selfData.scale]; context.TranslateT[[selfData.x, selfData.y]]; w _ selfData.lowerGraphEnd; IF NOT CEG.ThreeOrMoreVertices[w] THEN { context.SetColor[ImagerColor.ColorFromAtom[$Black]]; LineDrawGraph[context: context, v: w, showClientData: FALSE, showVerticesOnly: FALSE, labelVertices: FALSE] } ELSE { v _ CEG.SpecialPreviousOutlineVertex[w]; FillDrawRegionList[context, CEG.InternalPolygons[ v, w ] ]; CEG.ClearEdgeVisitedFields[v, w]; }; w _ selfData.upperGraphEnd; IF NOT CEG.ThreeOrMoreVertices[w] THEN { context.SetColor[ImagerColor.ColorFromAtom[$Black]]; LineDrawGraph[context: context, v: w, showClientData: FALSE, showVerticesOnly: FALSE, labelVertices: FALSE] } ELSE { v _ CEG.SpecialPreviousOutlineVertex[w]; FillDrawRegionList[context, CEG.InternalPolygons[ v, w ] ]; CEG.ClearEdgeVisitedFields[v, w]; }; }; <> ip: ImagerInterpress.Ref _ ImagerInterpress.Create[Rope.Cat["///Users/Arnon.pa/Combiner/Art", Convert.RopeFromCard[interpressIndex], ".ip"] ]; interpressIndex _ interpressIndex + 1; ImagerInterpress.DoPage[ip, action]; ImagerInterpress.Close[ip]; }; InitViewer: ViewerClasses.InitProc -- [self: ViewerClasses.Viewer] -- = { size: REAL = 100.0; self.data _ NEW[CombinerViewerDataRec _ [ lowerGraphEnd: NIL, upperGraphEnd: NIL, lowerGraphRegions: NIL, x: 0.0, y: 0.0 ]]; self.name _ "TestBasicCombiner"; }; Notify: ViewerClasses.NotifyProc -- [self:ViewerClasses.Viewer,input:LIST OF REF ANY] -- ={ xy: TIPUser.TIPScreenCoords _ NARROW[input.first]; <> point: CP.Point; clearVal: BOOL _ TRUE; selfData: CombinerViewerData _ NARROW[self.data]; <> <> point.x _ (1.0 / selfData.scale) * xy.mouseX - selfData.x; point.y _ (1.0 / selfData.scale) * xy.mouseY - selfData.y; SELECT input.rest.first FROM $RedRelease => { IF upperGraphOpen THEN { IF pointCount < 2 THEN { IF pointCount = 0 THEN { firstPoint _ point; pointCount _ 1; } ELSE { upperGraphEnd _ CP.CreatePolygon[firstPoint, point, globalClientData]; selfData.upperGraphEnd _ upperGraphEnd; pointCount _ 2; } } ELSE { CP.AddPointToPolygon[point, upperGraphEnd]; selfData.upperGraphEnd _ upperGraphEnd; pointCount _ pointCount + 1; }; ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE]; }; }; ENDCASE => ERROR; }; Paint: ViewerClasses.PaintProc = { <<[self: Viewer, context: Imager.Context, whatChanged: REF, clear: BOOL]>> <> FillDrawViewerGraphs: PROC ~ { v, w: CEG.ConvexEuclideanGraph; context.ScaleT[selfData.scale]; context.TranslateT[[selfData.x, selfData.y]]; w _ selfData.lowerGraphEnd; IF NOT CEG.ThreeOrMoreVertices[w] THEN { context.SetColor[ImagerColor.ColorFromAtom[$Black]]; LineDrawGraph[context: context, v: w, showClientData: FALSE, showVerticesOnly: FALSE, labelVertices: FALSE] } ELSE { v _ CEG.SpecialPreviousOutlineVertex[w]; FillDrawRegionList[context, CEG.InternalPolygons[v, w] ]; CEG.ClearEdgeVisitedFields[v, w]; }; w _ selfData.upperGraphEnd; IF NOT CEG.ThreeOrMoreVertices[w] THEN { context.SetColor[ImagerColor.ColorFromAtom[$Black]]; LineDrawGraph[context: context, v: w, showClientData: FALSE, showVerticesOnly: FALSE, labelVertices: FALSE] } ELSE { v _ CEG.SpecialPreviousOutlineVertex[w]; FillDrawRegionList[context, CEG.InternalPolygons[v, w] ]; CEG.ClearEdgeVisitedFields[v, w]; }; }; FillDrawLowerRegions: PROC ~ { L: CP.RegionGenerator; context.ScaleT[selfData.scale]; context.TranslateT[[selfData.x, selfData.y]]; L _ selfData.lowerGraphRegions; IF L#NIL THEN { v, w: CEG.ConvexEuclideanGraph; w _ selfData.lowerGraphEnd; v _ CEG.SpecialPreviousOutlineVertex[w]; FillDrawRegionGenerator[context, L]; CEG.ClearEdgeVisitedFields[v, w]; }; }; LineDrawViewerGraphs: PROC ~ { rgb: ImagerColor.RGB; context.ScaleT[selfData.scale]; context.TranslateT[[selfData.x, selfData.y]]; rgb _ [1.0, 0.0, 0.0]; -- red context.SetColor[ImagerColor.ColorFromRGB[rgb]]; LineDrawGraph[context: context, v: selfData.lowerGraphEnd, showClientData: showClientData, showVerticesOnly: showVerticesOnly, labelVertices: labelVertices]; rgb _ [0.0, 1.0, 0.0]; -- green context.SetColor[ImagerColor.ColorFromRGB[rgb]]; LineDrawGraph[context: context, v: selfData.upperGraphEnd, showClientData: showClientData, showVerticesOnly: showVerticesOnly, labelVertices: labelVertices]; }; LineDrawLowerRegions: PROC ~ { w: CP.RegionGenerator; context.ScaleT[selfData.scale]; context.TranslateT[[selfData.x, selfData.y]]; w _ selfData.lowerGraphRegions; IF w#NIL THEN { context.SetColor[ImagerColor.ColorFromAtom[$Black]]; LineDrawRegionGenerator[context, w]; }; }; selfData: CombinerViewerData _ NARROW[self.data]; <> SELECT whatChanged FROM NIL => { IF showGraphs THEN { IF fillDraw THEN context.DoSaveAll[FillDrawViewerGraphs] ELSE context.DoSaveAll[LineDrawViewerGraphs]; } ELSE { IF fillDraw THEN context.DoSaveAll[FillDrawLowerRegions] ELSE context.DoSaveAll[LineDrawLowerRegions]; }; }; ENDCASE => ERROR; }; RegisterCombinerViewerClass: PROC ~ { menu: Menus.Menu _ Menus.CreateMenu[4]; 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: DumpLowerGraph], line:0]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"LoadLower ", proc: ReadLowerGraph], line:0]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"DumpBoth ", proc: DumpBothGraphs], line:0]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"LoadBoth ", proc: ReadBothGraphs], line:0]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"IP ", proc: ObjectsToInterpress], 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:"Combine ", proc: RunCombiner], line:1]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Clean ", proc: RunCleaner], line:1]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"GetLowRegions ", proc: GetLowerRegions], line:1]; <> Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Red", proc: GlobalStateRed], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Green", proc: GlobalStateGreen], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Blue", proc: GlobalStateBlue], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"White", proc: GlobalStateWhite], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Black", proc: GlobalStateBlack], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Step", proc: StepGlobalState], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"SetUppState ", proc: SetUpperPolygonClientData], line:2]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"StateGeometry ", proc: StateGeometry], line:3]; <> <> Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"FillNoFill ", proc: FillNoFill], line:3]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"GraphsRegions ", proc: GraphsRegions], line:3]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Zoom ", proc: Zoom], line:3]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Horizontal ", proc: Horizontal], line:3]; Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"Vertical ", proc: Vertical], line:3]; combinerViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ flavor: $CombinerViewer, init: InitViewer, notify: Notify, tipTable: TIPUser.InstantiateNewTIPTable["ConvexCombiner.tip"], paint: Paint, menu: menu ]]; ViewerOps.RegisterViewerClass[flavor: $CombinerViewer, class: combinerViewerClass]; }; <<**** Top level variables>> <<>> <> <> <> globalClientData: REF; interpressIndex: CARDINAL _ 1; <<(Lower and Upper) Graph display options>> showClientData: BOOL _ TRUE; -- global variables for control of CEG.ConvexEuclideanGraph display format showVerticesOnly: BOOL _ FALSE; labelVertices: BOOL _ TRUE; fillDraw: BOOL _ TRUE; showGraphs: BOOL _ TRUE; <> lowerGraphEnd: CP.DBID; -- The convention is that if the lower structure exists, then lowerGraphEnd is one of its outline vertices. lowerGraphRegions: CP.RegionGenerator; <> upperGraphStart, upperGraphEnd: CP.PolyID; -- The convention is that if the upper structure exists, then upperGraphEnd is one of its outline vertices upperGraphOpen: BOOLEAN; -- true when an upperGraphEnd (which currently must be a polygon) is being read in saveVertexIndex: INT; -- for backup if unacceptable upperGraphEnd read pointCount: CARDINAL; firstPoint: CP.Point; <> out: IO.STREAM; verbosity: Verbosity _ NEW[CEG.VerbosityRec _ [in: NIL, out: NIL] ]; <<>> <> Color: TYPE = REF ImagerColor.RGB; <<>> <> clientDataFromRope: CEG.ClientDataFromRope ~ { char: CHAR; dataStream: IO.STREAM _ IO.RIS[rope]; red, green, blue: REAL; clientData: Color; DataFromRopeFail: PUBLIC ERROR [subclass: ATOM _ $Unspecified] = CODE; char _ dataStream.GetChar[]; IF char # '( THEN DataFromRopeFail[$LeftParenExpected]; red _ IO.GetReal[ dataStream]; []_ dataStream.SkipWhitespace[]; char _ dataStream.GetChar[]; IF char # '/ THEN DataFromRopeFail[$SlashExpected]; green _ IO.GetReal[ dataStream]; []_ dataStream.SkipWhitespace[]; char _ dataStream.GetChar[]; IF char # '/ THEN DataFromRopeFail[$SlashExpected]; blue _ IO.GetReal[ dataStream]; []_ dataStream.SkipWhitespace[]; char _ dataStream.GetChar[]; IF char # ') THEN DataFromRopeFail[$RightParenExpected]; clientData _ NEW[ImagerColor.RGB _ [R: red, G: green, B: blue] ]; RETURN[clientData]; }; ropeFromClientData: CEG.RopeFromClientData ~ { clientData: Color _ NARROW[ref]; out: Rope.ROPE; IF clientData = NIL THEN out _ Rope.Concat[out, "NIL"] ELSE out _ Rope.Cat[out, "(", Convert.RopeFromReal[clientData.R], "/", Rope.Cat[Convert.RopeFromReal[clientData.G], "/", Convert.RopeFromReal[clientData.B], ")"] ]; RETURN[out]; }; clientDataEqual: CP.RegionGlueProc ~ { color1, color2: Color; tol: REAL _ 0.005; IF clientData1=NIL OR clientData2=NIL THEN RETURN[clientData1=NIL AND clientData2 = NIL]; -- all ClientDataEqual's should contain this test color1 _ NARROW[clientData1]; color2 _ NARROW[clientData2]; RETURN[ ABS[color1.R - color2.R] < tol AND ABS[ color1.G - color2.G] < tol AND ABS[ color1.B - color2.B ] < tol ]; }; isA: CP.IsAProc ~ { -- This one differentiates red and not red color: Color; tol: REAL _ 0.005; IF clientData = NIL THEN RETURN[FALSE]; color _ NARROW[clientData]; RETURN[ ABS[color.R - 1.0] < tol AND ABS[ color.G - 0.0] < tol AND ABS[ color.B - 0.0 ] < tol ]; }; clientDataCombiner: CP.RegionOverlapProc = { currentColor: Color _ NARROW[currentClientdata]; inputColor: Color _ NARROW[inputClientdata]; red, green, blue: REAL; IF currentColor=NIL THEN RETURN[inputColor]; IF inputColor=NIL THEN RETURN[currentColor]; -- all ClientDataCombiner's should contain these two lines IF inputColor.R > 0.995 AND inputColor.G < 0.005 AND inputColor.B < 0.005 THEN RETURN[ NEW[ImagerColor.RGB _ [R: 1.0, G: 0.0, B: 0.0] ] ]; -- red is positive area red _ MIN[currentColor.R + inputColor.R, 1.0]; green _ MIN[currentColor.G + inputColor.G, 1.0]; blue _ MIN[currentColor.B + inputColor.B, 1.0]; RETURN[ NEW[ImagerColor.RGB _ [R: red, G: green, B: blue] ] ] }; <<**** End of Top level variables>> <<>> RegisterCombinerViewerClass[]; <> globalClientData _ NIL; lowerGraphEnd _ CP.CreateDatabase[]; lowerGraphRegions _ NIL; upperGraphStart _ upperGraphEnd _ CP.CreateDatabase[]; upperGraphOpen _ FALSE; [] _ ViewerOps.CreateViewer[flavor: $CombinerViewer, info: [iconic:FALSE, column: color] ]; <> <<>> <> <> <<[in, out] _ ViewerIO.CreateViewerStreams[logTitle];>> <> <> [] _ Random.Create[range: 0, seed: -1]; END. <<>>