SimpleCombinerTester.mesa
Last Edited by: Arnon, June 20, 1985 4:46:23 pm PDT
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: BOOLTRUE, showVerticesOnly: BOOLFALSE, labelVertices: BOOLTRUE ] = {
This algorithm assumes that a PlaneStructure is an RVHU.VertexHandleList. 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.VECRVHU.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] = {
Assumes two or more vertices
vAdjList: RVHU.AdjacencyHandleList ← v.adjacentVertices;
lastVertex, nextVertex: PlaneStructure;
done: BOOL;
vToNext, NextTov: RVHU.AdjacencyHandle;
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
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.VECRVHU.ImagerVecFromPoint[v.coordinates];
p2: Imager.VECRVHU.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: BOOLTRUE;
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;
};
Test that the polygon is convex; first need to get preceding vertex Note that the call to PreviousOutlineVertex amounts to an assumption that the polygon has at least three vertices. ConvexPolygon( or PreviousOutlineVertex?) will loop if < three vertices.
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;
Generate random points, compute convex hull,
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: BOOLTRUE;
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]
See ImagerInterpress to expand to write Interpress master, /indigo/peach for how to use Versatec
RenderPolygons: PROC ~ {
v, w: PlaneStructure;
rgbHandle: REF ImagerColor.RGBNARROW[selfData.lowerExternalState];
context.SetColor[ImagerColor.ColorFromRGB[rgbHandle^]];
context.MaskRectangleI[self.cx, self.cy, self.cw, self.ch];
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.SetColor[ImagerColor.ColorFromRGB[rgb]];
context.MaskRectangleI[self.cx, self.cy, self.cw, self.ch];
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];
context.ScaleT[0.0254/72]; -- conversion from meters to inches not needed????
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
Combiner Log title
logTitle: Rope.ROPE;
Global objects
globalState: CSI.State;
globalOutlineList: LIST OF SCB.Outline;
(Lower and Upper) Structure display options
showState: BOOLTRUE; -- global variables for control of PlaneStructure display format
showVerticesOnly: BOOLFALSE;
labelVertices: BOOLTRUE;
fillDraw: BOOLTRUE;
Lower Structure objects
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).
Upper Structure objects
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[];
Step through Reset procedure, creating CombinerViewer along the way (in place of painting the existing viewer), and relying on InitViewer to set PlaneStructure fields of viewer (in place of setting them explicitly).
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] ];
End of Step through Reset procedure
Create Combiner Log
logTitle ← IO.PutFR["Combiner Log"];
[RCB.in, RCB.out] ← ViewerIO.CreateViewerStreams[logTitle];
Initialize random numbers
[] ← Random.Create[range: 0, seed: -1];
END.