-- File CIFDrcScan.mesa -- Written by Dan Fitzpatrick and Martin Newell, August 1980 -- Last updated: March 25, 1981 4:31 PM DIRECTORY BitBltDefs: FROM "BitBltDefs", --CGraphicsDefs: FROM "CGraphicsDefs" USING [Transform], CIFDevicesDefs: FROM "CIFDevicesDefs" USING [MaxLENGTHLayerArray, LENGTHLayerArray], CIFOutputDefs: FROM "CIFOutputDefs" USING [SetSorting], CIFDrcScanDefs: FROM "CIFDrcScanDefs", CIFDrcNMOSDefs: FROM "CIFDrcNMOSDefs" USING[InitDrcNMOS, FinishDrcNMOS, NewSwath, CheckTrap], CIFDrcUtilsDefs: FROM "CIFDrcUtilsDefs" USING[Edge, EdgeRecord, MakeEdge, FreeEdge, WriteLongOctal, WriteFloat], IntDefs: FROM "IntDefs" USING[IBoundBox], IODefs: FROM "IODefs" USING [SP, CR, WriteString, WriteLine, WriteChar, WriteDecimal]; --MoreTrapezoidDefs: FROM "MoreTrapezoidDefs" USING [SetOutputTrapezoid, -- GetDefaultOutputTrapezoid], --TrapezoidDefs: FROM "TrapezoidDefs" USING [TrapezoidBlock], --XDisplayDefs: FROM "XDisplayDefs"; CIFDrcScan: PROGRAM IMPORTS CIFDevicesDefs, CIFDrcNMOSDefs, CIFDrcUtilsDefs, CIFOutputDefs, IntDefs, IODefs EXPORTS CIFDrcScanDefs = BEGIN OPEN CIFDevicesDefs, CIFDrcNMOSDefs, CIFDrcUtilsDefs, CIFOutputDefs, IntDefs, IODefs; -- Drc procedures DrcScanStart: PUBLIC PROCEDURE [fileName: STRING] = BEGIN l,r,b,t: LONG INTEGER; [l,r,b,t] _ IBoundBox[]; --Initialize EdgeList and ActiveList EdgeList _ EdgeListEl _ ActiveList _ ALL[NIL]; SetSorting[incy]; YNext _ YCurr _ YPrev _ ALL[b]; --i.e.not set VStripeBottom _ b; VStripeTop _ b + 3*Lambda; InitDrcNMOS[fileName, Lambda, l,b,r,t]; END; DrcScanEnd: PUBLIC PROCEDURE [ymax: REAL] = BEGIN --ymax is REAL, that gives ymax of picture l,r,b,t: LONG INTEGER; [l,r,b,t] _ IBoundBox[]; ymax _ t; ymax _ t + 9 * Lambda; UNTIL VStripeBottom>ymax+1 DO --1+ is kludge to make sure it all gets out DrcNextStripe[]; ENDLOOP; NewSwath[VStripeBottom,VStripeBottom]; FinishDrcNMOS[]; END; DrcTrigger: PUBLIC PROCEDURE [bottom: REAL] = --used to trigger scan conversion up to bottom of object about to be received BEGIN WHILE bottom>=VStripeTop DO DrcNextStripe[]; ENDLOOP; --***IF VStripeBottom < bottom THEN NewSwath[VStripeBottom,bottom]; ** The usual case --***DrcScanConvert[bottom, FALSE]; END; --Private procedures-- DrcNextStripe: PROCEDURE = BEGIN --finish off and output current stripe, and step to next NewSwath[VStripeBottom,VStripeTop]; DrcScanConvert[VStripeTop, FALSE]; DrcScanConvert[VStripeTop, TRUE]; VStripeBottom _ VStripeTop; VStripeTop _ VStripeTop + 3*Lambda; END; MakeLongPointer: PROCEDURE[low,high: UNSPECIFIED] RETURNS[LONG POINTER] = MACHINE CODE BEGIN --nothing to do-- END; BreakLongPointer: PROCEDURE[lptr: LONG POINTER] RETURNS[low,high: UNSPECIFIED] = MACHINE CODE BEGIN --nothing to do-- END; DrcScanConvert: 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: LONG 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 HorLine[XatY[segleft,YCurr[layer]], XatY[e,YCurr[layer]], YCurr[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 CheckTrap[e1,e2,e1.lastouty,ytop,layer]; 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; EnterEdge[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; GetEdge: 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; 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; QueueForEdgeList: PROCEDURE[e: Edge] = BEGIN e.next _ EdgeListQueue; EdgeListQueue _ e; END; XatY: PROCEDURE[edge: Edge, y: REAL] RETURNS[x: REAL] = BEGIN RETURN[ WITH e:edge SELECT IF edge.vert THEN vertical ELSE oblique FROM oblique => --i.e. oblique SELECT TRUE FROM y=e.ystart => e.xstart, y=e.yend => e.xend, ENDCASE => e.xstart + (y-e.ystart)*e.slope, --must compute from consistent end! ENDCASE => edge.xstart --i.e. vertical ]; 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; HorLine: PROCEDURE[xleft,xright,y: REAL] = BEGIN IF xleft=xright THEN RETURN; END; DrawTrap: PROCEDURE[left: Edge, ystart: REAL, right: Edge, yend: REAL, layer: CARDINAL] = BEGIN --draw left and right edges on screen for now --left edge END; --AllocateVerticalEdge: PROCEDURE RETURNS[Edge] = -- BEGIN -- RETURN[AllocateHeapNode[SIZE[vertical EdgeRecord]]]; -- END; --AllocateObliqueEdge: PROCEDURE RETURNS[Edge] = -- BEGIN -- RETURN[AllocateHeapNode[SIZE[oblique EdgeRecord]]]; -- END; --FreeEdge: PROCEDURE[edge: Edge] = -- BEGIN -- FreeHeapNode[edge]; -- END; EnterEdge: PUBLIC PROCEDURE[layer: CARDINAL, edge: Edge] = BEGIN e,save,start: Edge; y: REAL _ edge.ystart; start _ EdgeListEl[layer]; EdgeListEl[layer] _ edge; IF EdgeList[layer]=NIL THEN BEGIN edge.next _ NIL; edge.mate _ NIL; EdgeList[layer] _ edge; RETURN; END; IF start=NIL THEN start _ EdgeList[layer]; --search forward save _ NIL; FOR e _ start, e.next UNTIL e=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: PROCEDURE[layer: CARDINAL] RETURNS[edge: Edge] = --Returns next edge from EdgeList without removing it from EdgeList BEGIN edge _ EdgeList[layer]; END; GetFromEdgeList: 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; EdgeListEl[layer] _ edge.next; edge.mate _ NIL; --clean up END; END; -- EdgeLessThan: PROCEDURE[e1,e2: Edge, y: REAL] RETURNS[BOOLEAN] = BEGIN --orders up/down within slope within x x1: REAL _ XatY[e1,y]; x2: REAL _ XatY[e2,y]; RETURN[x1 WriteLine["ActiveList"]; EdgeList[layer] => WriteLine["EdgeList"]; ENDCASE; WriteLongOctal[list]; WriteChar[CR]; FOR e _ list, e.next UNTIL e=NIL DO WriteString["next:"]; WriteLongOctal[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:"]; WriteLongOctal[e.mate]; WriteChar[SP]; WriteString["XatYCurr: "]; WriteFloat[XatY[e,YCurr[layer]]]; WriteChar[CR]; WriteChar[CR]; ENDLOOP; END; SetLambda: PUBLIC PROCEDURE[l:REAL] = BEGIN Lambda _ l*Shrinkage; END; EdgeList,EdgeListEl,ActiveList: ARRAY [0..MaxLENGTHLayerArray) OF Edge; EdgeListQueue: Edge; --isolates edges being thrown back onto edge list EdgeType: TYPE = {acontinuingUp, acontinuingDown, aterminatingUp, aterminatingDown, estartingUp, estartingDown, null}; YNext,YCurr,YPrev: ARRAY [0..MaxLENGTHLayerArray) OF REAL; VStripeBottom,VStripeTop: REAL; --limits to be mapped onto current stripe VStripeWidth: CARDINAL _ 3472; --***should be wired to required buffer width Num: REAL _ 999; Den: REAL _ 1000; Shrinkage: REAL _ Num/Den; -- Shrink lambda by 0.1% to avoid roundoff errors Lambda: REAL _ 250*Shrinkage; END. (635)\127b9B811b10B237b12B345b10B338b10B332b13B259b15B105b16B111b14B352b12B48b10B114b9B55b7B445b7B260b27B326b16B3752b7B297b8B163b18B271b16B763b17B1268b16B82b4B367b4B206b5B200b7B80b8B154b22B28b2B7b2B54b2B7b21B28b2B7b2B53b2B7b10B26b2B7b2B21b2B7b9B1153b14B158b15B335b12B260b9B1329b9B