-- File CIFRamtekScan.mesa -- Written by Martin Newell, June 1980 -- Last updated: September 29, 1981 10:28 AM by Pasco DIRECTORY CIFDevicesDefs: FROM "CIFDevicesDefs" USING [MaxLENGTHLayerArray, LENGTHLayerArray], CIFRamtekScanDefs: FROM "CIFRamtekScanDefs", CIFRamtekTypeDefs: FROM "CIFRamtekTypeDefs" USING [Edge, EdgeRecord, EdgeAngle, EdgeType], CIFRamtekUtilsDefs: FROM "CIFRamtekUtilsDefs" USING[ VersatecMakeEdge, FreeEdge, EdgeLessThan, XatY, HorColorLine, DrawTrap], IODefs: FROM "IODefs" USING [SP, CR, WriteString, WriteLine, WriteOctal, WriteChar, WriteDecimal], Real: FROM "Real" USING [WriteReal]; CIFRamtekScan: PROGRAM IMPORTS CIFDevicesDefs, CIFRamtekUtilsDefs, IODefs, Real EXPORTS CIFRamtekScanDefs = BEGIN OPEN CIFDevicesDefs, CIFRamtekTypeDefs, CIFRamtekUtilsDefs, IODefs, Real; InitRamtekScan: PUBLIC PROCEDURE = BEGIN --Initialize EdgeList and ActiveList EdgeList _ EdgeListEl _ ActiveList _ ALL[NIL]; YNext _ YCurr _ YPrev _ ALL[0]; --i.e.not set END; RamtekScanConvert: PUBLIC PROCEDURE [upto: REAL, forceOutput: BOOLEAN] = -- Run the scan converter up to y=upto -- forceOutput forces output up to and including upto BEGIN edge,prevedge: Edge; edgetype: EdgeType; newActiveList,pendingFreeEdges,nextedge: Edge; ptrnewActiveList: POINTER TO Edge; i,layer: CARDINAL; segleft,trapleft: Edge; adepth,edepth: INTEGER; StartSegment: PROCEDURE[e: Edge] = BEGIN segleft _ e; END; EndSegment: PROCEDURE[e: Edge] = BEGIN HorColorLine[XatY[segleft,YCurr[layer]], XatY[e,YCurr[layer]], YCurr[layer], layer]; END; StartTrap: PROCEDURE[e: Edge] = BEGIN trapleft _ e; END; EndTrap: PROCEDURE[right: Edge] = BEGIN left: Edge _ trapleft; IF left.mate#right THEN BEGIN --pairing changed or NIL OutTrap[left,YPrev[layer]]; OutTrap[right,YPrev[layer]]; left.mate _ right; right.mate _ left; END; IF left.flagout OR right.flagout OR forceOutput THEN BEGIN OutTrap[left,YCurr[layer]]; left.flagout _ right.flagout _ FALSE; --mustn't do this in OutTrap because of other calls to it END; END; OutTrap: PROCEDURE[e1: Edge, ytop: REAL] = BEGIN e2: Edge _ e1.mate; IF e2#NIL THEN BEGIN DrawTrap[e1,e1.lastouty,e2,ytop,layer]; e1.lastouty _ e2.lastouty _ ytop; e1.mate _ e2.mate _ NIL; END; END; UpdateYNextNewALAndprevedge: PROCEDURE[edge: Edge] = --Update YNext, newActiveList, and prevedge BEGIN --YNext: YNext[layer] _ CheckIntersection[prevedge,edge,YCurr[layer],MIN[YNext[layer],edge.yend]]; --newActiveList: edge.next _ NIL; ptrnewActiveList^ _ edge; ptrnewActiveList _ @edge.next; --and prevedge: prevedge _ edge; END; QueueForFreeEdge: PROCEDURE[edge: Edge] = BEGIN edge.next _ pendingFreeEdges; pendingFreeEdges _ edge; END; FOR layer IN [0..LENGTHLayerArray) DO UNTIL (forceOutput AND YPrev[layer]>=upto) OR (~forceOutput AND YNext[layer]>=upto) OR (ActiveList[layer]=NIL AND EdgeList[layer]=NIL) DO --in one pass through each ActiveList: -- output trapezoids in previous swath -- remove terminating edges from previous swath, -- introduce newly entering ones, -- drawing capping lines as necessary, -- and find lowest upper y in YNext adepth _ edepth _ 0; [edge,edgetype] _ GetEdge[layer]; prevedge _ NIL; YNext[layer] _ upto; pendingFreeEdges _ NIL; newActiveList _ EdgeListQueue _ NIL; ptrnewActiveList _ @newActiveList; IF YCurr[layer]=YPrev[layer] THEN BEGIN --scan only to find YNext[layer] (and therefore to do intersections) UNTIL edge=NIL DO SELECT edgetype FROM aterminatingUp,aterminatingDown => QueueForFreeEdge[edge]; acontinuingUp,acontinuingDown,estartingUp,estartingDown => UpdateYNextNewALAndprevedge[edge]; ENDCASE; [edge,edgetype] _ GetEdge[layer]; ENDLOOP; END ELSE BEGIN --normal case UNTIL edge=NIL DO SELECT edgetype FROM aterminatingUp => BEGIN IF adepth=0 THEN BEGIN edge.flagout _ TRUE; StartTrap[edge]; IF edepth#0 THEN EndSegment[edge] ELSE StartSegment[edge]; END; adepth _ adepth+1; QueueForFreeEdge[edge]; END; aterminatingDown => BEGIN adepth _ adepth-1; IF adepth=0 THEN BEGIN edge.flagout _ TRUE; EndTrap[edge]; IF edepth=0 THEN EndSegment[edge] ELSE StartSegment[edge]; END; QueueForFreeEdge[edge]; END; acontinuingUp => BEGIN UpdateYNextNewALAndprevedge[edge]; --must do this first incase intersection set .flagout IF adepth=0 THEN BEGIN IF edepth#0 THEN BEGIN edge.flagout _ TRUE; EndSegment[edge]; END; StartTrap[edge]; END ELSE BEGIN IF edepth=0 THEN BEGIN edge.lastouty _ YCurr[layer]; EndSegment[edge]; END; END; adepth _ adepth+1; edepth _ edepth+1; END; acontinuingDown => BEGIN UpdateYNextNewALAndprevedge[edge]; adepth _ adepth-1; edepth _ edepth-1; IF adepth=0 THEN BEGIN IF edepth#0 THEN BEGIN edge.flagout _ TRUE; StartSegment[edge]; END; EndTrap[edge]; END ELSE BEGIN IF edepth=0 THEN BEGIN edge.lastouty _ YCurr[layer]; StartSegment[edge]; END; END; END; estartingUp => BEGIN UpdateYNextNewALAndprevedge[edge]; IF edepth=0 THEN IF adepth#0 THEN EndSegment[edge] ELSE StartSegment[edge]; edepth _ edepth+1; END; estartingDown => BEGIN UpdateYNextNewALAndprevedge[edge]; edepth _ edepth-1; IF edepth=0 THEN IF adepth=0 THEN EndSegment[edge] ELSE StartSegment[edge]; END; ENDCASE; [edge,edgetype] _ GetEdge[layer]; ENDLOOP; END; ActiveList[layer] _ newActiveList; FOR edge _ pendingFreeEdges,nextedge UNTIL edge=NIL DO nextedge _ edge.next; FreeEdge[edge]; ENDLOOP; FOR edge _ EdgeListQueue,nextedge UNTIL edge=NIL DO nextedge _ edge.next; AddToEdgeList[layer,edge]; ENDLOOP; IF EdgeList[layer]#NIL THEN YNext[layer] _ MIN[YNext[layer],EdgeList[layer].ystart]; YPrev[layer] _ YCurr[layer]; YCurr[layer] _ YNext[layer]; ENDLOOP; --UNTIL (... ENDLOOP; --FOR layer ... FOR i IN [0..LENGTHLayerArray) DO --because next entry requires re-finding YNext[layer] YCurr[layer] _ YPrev[layer]; ENDLOOP; END; CheckIntersection: PROCEDURE[e1,e2: Edge, ylow,yhigh: REAL] RETURNS[y: REAL] = --check for and deal with intersection of e1 and e2 between ylow and yhigh --Returns either yhigh or y of intersection --assumes edges are in order at ylow BEGIN IF e1#NIL AND XatY[e1,yhigh]>XatY[e2,yhigh] THEN BEGIN xint,yint: REAL; s1: REAL _ Slope[e1]; s2: REAL _ Slope[e2]; yint _ IF s1#s2 THEN MAX[ylow, MIN[yhigh, ((e2.ystart*s2 - e1.ystart*s1)-(e2.xstart - e1.xstart))/(s2 - s1)]] ELSE yhigh; xint _ XatY[IF e1.vert THEN e1 ELSE e2,yint]; --put upper fragments back onto edgeList IF yint e.xend _ xint; ENDCASE; e1.yend _ yint; WITH e:e2 SELECT IF e2.vert THEN vertical ELSE oblique FROM oblique => e.xend _ xint; ENDCASE; e2.yend _ yint; IF yint=ylow THEN e1.flagout _ e2.flagout _ TRUE; RETURN[yint]; END ELSE RETURN[yhigh]; END; -- The next 3 procedures (AddToEdgeList, PeekAtEdgeList, GetFromEdgeList) implement -- the EdgeList and are subject to replacement -- In this version the EdgeList is kept doubly linked and search for -- insertion place is started at last-inserted Edge -- Back pointers use the .mate field --AddToEdgeList: PROCEDURE[layer: CARDINAL, edge: Edge] = -- BEGIN -- eptr: POINTER TO Edge; -- y: REAL _ edge.ystart; -- FOR eptr _ @EdgeList[layer], @eptr.next UNTIL eptr^=NIL DO -- IF y BEGIN --edge "<" e FOR e _ e.mate, e.mate UNTIL e=NIL DO IF e.ystart BEGIN --append edge to e edge.next _ e.next; edge.mate _ e; e.next.mate _ edge; e.next _ edge; RETURN; END; ENDLOOP; --reached begin of list - insert edge before 1st element edge.next _ EdgeList[layer]; edge.mate _ NIL; EdgeList[layer].mate _ edge; EdgeList[layer] _ edge; RETURN; END; ENDLOOP; --reached end of list - append edge to save edge.next _ NIL; edge.mate _ save; save.next _ edge; END; PeekAtEdgeList: PUBLIC PROCEDURE[layer: CARDINAL] RETURNS[edge: Edge] = --Returns next edge from EdgeList without removing it from EdgeList BEGIN edge _ EdgeList[layer]; END; GetFromEdgeList: PUBLIC PROCEDURE[layer: CARDINAL] RETURNS[edge: Edge] = --Returns next edge from EdgeList having removed it from EdgeList BEGIN edge _ EdgeList[layer]; IF edge#NIL THEN BEGIN EdgeList[layer] _ edge.next; IF edge.next#NIL THEN edge.next.mate _ NIL; --***IF new EdgeListEl[layer] _ edge.next; edge.mate _ NIL; --clean up END; END; GetEdge: PUBLIC PROCEDURE[layer: CARDINAL] RETURNS[edge: Edge, edgeType: EdgeType] = --Get next edge for new active list - filter out zero height edges BEGIN DO [edge,edgeType] _ GetEdge1[layer]; IF edge=NIL OR edge.yend>edge.ystart THEN EXIT; FreeEdge[edge]; --exists and zero height ENDLOOP; END; GetEdge1: PROCEDURE[layer: CARDINAL] RETURNS[edge: Edge, edgeType: EdgeType] = --Get next edge for new active list BEGIN peekAtEdgeList: Edge _ PeekAtEdgeList[layer]; TakeFromActiveList: PROCEDURE = BEGIN edge _ ActiveList[layer]; ActiveList[layer] _ ActiveList[layer].next; edgeType _ IF edge.yend<=YCurr[layer] THEN IF edge.up THEN aterminatingUp ELSE aterminatingDown ELSE IF edge.up THEN acontinuingUp ELSE acontinuingDown; END; TakeFromEdgeList: PROCEDURE = BEGIN edge _ GetFromEdgeList[layer]; edgeType _ IF edge.up THEN estartingUp ELSE estartingDown; --tidy it up edge.flagout _ FALSE; edge.lastouty _ edge.ystart; edge.mate _ NIL; END; SELECT TRUE FROM ActiveList[layer]=NIL => BEGIN --take it from EdgeList provided starting at YCurr IF peekAtEdgeList#NIL AND peekAtEdgeList.ystart <= YCurr[layer] THEN TakeFromEdgeList[] ELSE BEGIN edge _ NIL; edgeType _ null; END; END; peekAtEdgeList=NIL => TakeFromActiveList[]; -- must be non-NIL if get here ENDCASE => --both lists are candidates IF peekAtEdgeList.ystart <= YCurr[layer] AND EdgeLessThan[peekAtEdgeList,ActiveList[layer], YCurr[layer]] THEN TakeFromEdgeList[] ELSE TakeFromActiveList[]; END; QueueForEdgeList: PROCEDURE[e: Edge] = BEGIN e.next _ EdgeListQueue; EdgeListQueue _ e; END; Xend: PROCEDURE[edge: Edge] RETURNS[xend: REAL] = INLINE BEGIN RETURN[WITH e:edge SELECT IF edge.vert THEN vertical ELSE oblique FROM oblique => e.xend, ENDCASE => edge.xstart --i.e.vertical ]; END; Slope: PROCEDURE[edge: Edge] RETURNS[slope: REAL] = INLINE BEGIN RETURN[WITH e:edge SELECT IF edge.vert THEN vertical ELSE oblique FROM oblique => e.slope, ENDCASE => 0 --i.e.vertical ]; END; PrintList: PUBLIC PROCEDURE[list: Edge, layer: CARDINAL] = BEGIN e: Edge; WriteString["YPrev,YCurr,YNext["]; WriteDecimal[layer]; WriteString["]: "]; WriteFloat[YPrev[layer]]; WriteChar[',]; WriteFloat[YCurr[layer]]; WriteChar[',]; WriteFloat[YNext[layer]]; WriteChar[CR]; SELECT list FROM ActiveList[layer] => WriteLine["ActiveList"]; EdgeList[layer] => WriteLine["EdgeList"]; ENDCASE; WriteOctal[list]; WriteChar[CR]; FOR e _ list, e.next UNTIL e=NIL DO WriteString["next:"]; WriteOctal[e.next]; WriteChar[SP]; WriteString["xstart:"]; WriteFloat[e.xstart]; WriteChar[SP]; WriteString["ystart:"]; WriteFloat[e.ystart]; WriteChar[SP]; WriteString["xend:"]; WriteFloat[Xend[e]]; WriteChar[SP]; WriteString["yend:"]; WriteFloat[e.yend]; WriteChar[SP]; WriteString["slope:"]; WriteFloat[Slope[e]]; WriteChar[SP]; WriteString["slant:"]; WriteString[IF e.vert THEN "vertical" ELSE "oblique"]; WriteChar[SP]; WriteString["up:"]; WriteChar[IF e.up THEN 'T ELSE 'F]; WriteChar[SP]; WriteString["flagout:"]; WriteChar[IF e.flagout THEN 'T ELSE 'F]; WriteChar[SP]; WriteString["lastouty:"]; WriteFloat[e.lastouty]; WriteChar[SP]; WriteString["mate:"]; WriteOctal[e.mate]; WriteChar[SP]; WriteString["XatYCurr: "]; WriteFloat[XatY[e,YCurr[layer]]]; WriteChar[CR]; WriteChar[CR]; ENDLOOP; END; WriteFloat: PROCEDURE[r: REAL] = BEGIN WriteReal[WriteChar,r]; END; YNext,YCurr,YPrev: ARRAY [0..MaxLENGTHLayerArray) OF REAL; EdgeList,EdgeListEl,ActiveList: ARRAY [0..MaxLENGTHLayerArray) OF Edge; EdgeListQueue: Edge; --isolates edges being thrown back onto edge list END. (635)\f8 122b9B489b13B178b14B167b17B354b12B48b10B126b9B55b7B445b7B216b27B326b16B3756b17B1580b13B310b13B1153b14B165b15B348b7B304b8B163b18B271b16B763b16B82b4B206b5B200b9B1317b10B