CombinePolyTester.mesa
Last Edited by: Arnon, June 20, 1985 4:46:23 pm PDT
Pier, June 2, 1986 2:46:16 pm PDT
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
= 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;
};
Test that the polygon is convex; first need to get preceding vertex Note that the call to SpecialPreviousOutlineVertex amounts to an assumption that the polygon has at least three vertices. ConvexPolygon( or SpecialPreviousOutlineVertex?) will loop if < three vertices.
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;
out.PutF["\n\nVertexVerify lowerGraphEnd"];
maxVertexIndex ← EG.VertexVerifyIOGraph["///Users/Arnon.pa/Combiner/LowerGraph", out];
[lowerGraphEnd, numberVertices ] ← CEG.GraphFromFile["///Users/Arnon.pa/Combiner/LowerGraph", clientDataFromRope, out];
EG.vertexIndex ← MAX[maxVertexIndex, numberVertices]; -- don't repeat indices
out.PutF["\n\nVertexVerify upperGraphEnd"];
maxVertexIndex ← EG.VertexVerifyIOGraph["///Users/Arnon.pa/Combiner/UpperGraph", out];
out.PutF["\n"];
[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;
out.PutF["\n\nVertexVerify lowerGraphEnd"];
maxVertexIndex ← EG.VertexVerifyIOGraph["///Users/Arnon.pa/Combiner/LowerGraph", out];
[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];
};
EdgesVertices: Menus.MenuProc = {
self: CombinerViewer ← NARROW[parent, ViewerClasses.Viewer];
showVerticesOnly ← NOT showVerticesOnly;
labelVertices ← NOT labelVertices;
ViewerOps.PaintViewer[viewer: self, hint: client, whatChanged: NIL, clearClient: TRUE];
};
VertexLabels: Menus.MenuProc = {
self: CombinerViewer ← NARROW[parent, ViewerClasses.Viewer];
labelVertices ← NOT labelVertices;
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 ] ];
since globalClientData is a REF, need NEW[newrgb] to avoid changing previous versions.
out.PutF["\n StepInputColor sets globalClientData to %g, %g, %g", IO.real[newrgb.R], IO.real[newrgb.G], IO.real[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;
Generate 20 random points, compute convex hull,
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 ] = {
Does Depth First Search. Assumes context color already set.
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] = {
Assumes two or more vertices
vAdjList: EG.AdjacencyList ← v.adjacentVertices;
lastVertex, nextVertex: CEG.ConvexEuclideanGraph;
done: BOOL;
vToNext, NextTov: EG.Adjacency;
Record that we've visited v
v.visited ← visitedValue; -- record that we've visited this vertex
Recursive calls for adjacencies of v
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];
};
};
Get an interpress context from the rope, "display" only the visible objects
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];
x, y: RN.RatNum;
point: CP.Point;
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];
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]
See ImagerInterpress to expand to write Interpress master, /indigo/peach for how to use Versatec
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];
context.ScaleT[0.0254/72]; -- conversion from meters to inches not needed????
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:"RandTest", proc: RandomTest], 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:"EdgesVertices ", proc: EdgesVertices], line:3];
Menus.AppendMenuEntry[menu:menu, entry:Menus.CreateEntry [name:"VertexLabels ", proc: VertexLabels], 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
Combiner Log title
logTitle: Rope.ROPE;
Global objects
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;
Lower Graph objects
lowerGraphEnd: CP.DBID; -- The convention is that if the lower structure exists, then lowerGraphEnd is one of its outline vertices.
lowerGraphRegions: CP.RegionGenerator;
Upper Graph objects
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;
in: IO.STREAM;
out: IO.STREAM;
verbosity: Verbosity ← NEW[CEG.VerbosityRec ← [in: NIL, out: NIL] ];
Client data type
Color: TYPE = REF ImagerColor.RGB;
Client data procedures
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[];
Step through Reset procedure, creating CombinerViewer along the way (in place of painting the existing viewer), and relying on InitViewer to set CEG.ConvexEuclideanGraph fields of viewer (in place of setting them explicitly).
globalClientData ← NIL;
lowerGraphEnd ← CP.CreateDatabase[];
lowerGraphRegions ← NIL;
upperGraphStart ← upperGraphEnd ← CP.CreateDatabase[];
upperGraphOpen ← FALSE;
[] ← ViewerOps.CreateViewer[flavor: $CombinerViewer, info: [iconic:FALSE, column: color] ];
End of Step through Reset procedure
Create Combiner Log
logTitle ← IO.PutFR["Combiner Log"];
[in, out] ← ViewerIO.CreateViewerStreams[logTitle];
verbosity.in ← in; verbosity.out ← out;
Initialize random numbers
[] ← Random.Create[range: 0, seed: -1];
END.