DIRECTORY Atom USING [ GetPropFromList ], Real USING [ Round, LargestNumber ], ThreeDBasics USING [ Context, RealSequence, Rectangle, ShapeInstance ], Interactive3D USING [ CloseVertex, CloseVertexSequence, FacingDirection ]; Interactive3DImpl: CEDAR PROGRAM IMPORTS Atom, Real EXPORTS Interactive3D ~ BEGIN Context: TYPE ~ ThreeDBasics.Context; Rectangle: TYPE ~ ThreeDBasics.Rectangle; RealSequence: TYPE ~ ThreeDBasics.RealSequence; FacingDirection: TYPE ~ Interactive3D.FacingDirection; CloseVertex: TYPE ~ Interactive3D.CloseVertex; CloseVertexSequence: TYPE ~ Interactive3D.CloseVertexSequence; NearbyVertices: PUBLIC PROC[ context: Context, cursorX, cursorY: REAL, numberToReturn: NAT _ 1, maxDistance: REAL _ Real.LargestNumber ] RETURNS[ closeVtx: REF CloseVertexSequence ] ~ { closeDist: REF RealSequence _ NEW[ RealSequence[numberToReturn] ]; FOR i: NAT IN [0.. closeDist.length) DO closeDist[i] _ Real.LargestNumber; ENDLOOP; closeVtx _ NEW[ CloseVertexSequence[numberToReturn] ]; FOR i: NAT IN [0.. context.shapes.length) DO IF Atom.GetPropFromList[context.shapes[i].props, $Invisible] = NIL AND context.shapes[i].clipState # out AND Inside[context.shapes[i], cursorX, cursorY] THEN { shape: REF ThreeDBasics.ShapeInstance _ context.shapes[i]; FOR i: NAT IN [0.. shape.vertex.length) DO distance: REAL _ ABS[ cursorX - shape.vertex[i].sx ] + ABS[ cursorY - shape.vertex[i].sy ]; IF distance < maxDistance AND distance < closeDist[0] THEN { closeDist[0] _ distance; -- replace most distant close vertex found so far closeVtx[0] _ [i, shape]; FOR j: NAT IN [1 .. closeDist.length) DO -- bubble into sorted position IF closeDist[i] > closeDist[i-1] THEN { tmpVtx: CloseVertex; tmpDst: REAL; tmpDst _ closeDist[i-1]; closeDist[i-1] _ closeDist[i]; closeDist[i] _ tmpDst; tmpVtx _ closeVtx[i-1]; closeVtx[i-1] _ closeVtx[i]; closeVtx[i] _ tmpVtx; } ELSE EXIT; ENDLOOP; -- do for close Vertices }; ENDLOOP; -- do for all vertices }; ENDLOOP; -- do for all shapes }; Inside: PROC[ shape: REF ThreeDBasics.ShapeInstance, x, y: REAL ] RETURNS[ BOOLEAN ] ~ { ix: NAT _ Real.Round[x]; iy: NAT _ Real.Round[y]; IF shape.screenExtent.min.f > ix OR shape.screenExtent.max.f < ix OR shape.screenExtent.min.s > iy OR shape.screenExtent.max.s < iy THEN RETURN[ FALSE ] ELSE RETURN[ TRUE ]; }; BestPolygon: PUBLIC PROC[ closeVtx: REF CloseVertexSequence, facingDir: FacingDirection _ front, closest: BOOLEAN _ TRUE ] ~ { }; PasteOn: PUBLIC PROC[context: Context, viewPort: Rectangle, action: PROC[Context]] ~ { }; RipOff: PUBLIC PROC[ context: Context ] ~ { }; END. $Interactive3DImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last Edited by: Crow, June 10, 1989 1:47:12 pm PDT Basic Types RECORD[ vtx: NAT, shape: REF ThreeDBasics.ShapeInstance ]; RECORD[ SEQUENCE length: CARDINAL OF CloseVertex ]; Procedures for hit testing Procedures for erasable drawing Stores pixels underlying viewPort and saves them on context.props to RipOff the area later, if something is already stored on context.props it is RippedOff before action is executed. Action is executed within context using supplied viewPort. Undoes the last PasteOn srcExtent, dstExtent: Pixels.Extent; srcBuf: REF PixelBuffer _ NARROW[ Atom.GetPropFromList[context.props, $PasteOnBuffer] ]; IF srcBuf = NIL THEN RETURN[]; srcExtent _ Pixels.GetExtent[srcBuf^]; dstExtent _ Pixels.GetExtent[context.display]; Pixels.Clip[context.display, srcExtent]; Pixels.Transfer[context.display, srcBuf^]; Pixels.Clip[context.display, dstExtent]; -- restore buffer size context.props _ Atom.RemPropFromList[context.props, $PasteOnBuffer]; Κΰ˜Iheadšœ™šœ Οmœ1™Jšžœžœ žœžœ™3——šœ™šŸœžœžœ&žœžœžœžœ žœ˜ΛJ˜Idefaultšœ žœžœ!˜BMš žœžœžœžœ&žœ˜UMšœ žœ)˜7šžœžœžœžœ˜-šžœ=žœ˜CMšžœ"˜%Mšžœ,˜/šžœ˜Jšœžœ1˜;šžœžœžœž˜*Mšœ žœžœ(žœ!˜`šžœžœžœ˜