-- File: SVDrawImpl.mesa -- Last edited by Bier on December 18, 1982 1:32 am -- Author: Eric Bier on October 19, 1982 3:10 pm -- Contents: Some convenience functions to draw shapes not directly available in Cedar Graphics DIRECTORY Graphics, GraphicsColor, Real, RealFns, SV2d, SVDraw, SVLines2d, SVVector2d; SVDrawImpl: PROGRAM IMPORTS Graphics, Real, RealFns, SVLines2d, SVVector2d EXPORTS SVDraw = BEGIN Point2d: TYPE = SV2d.Point2d; globalSandwich: Graphics.Path _ Graphics.NewPath[2]; Circle: PUBLIC PROC [dc: Graphics.Context, originX, originY, radius: REAL] = { -- draw 1/8 of a circle carefully and get the rest by mirroring around vertical, horizontal, and 45 degree axes. -- as an exercise in flatness tests, I declared that a straight line adequately approximates an arc of the circle if the maximum deviation of the line from the circle is less than z pixel heights. Given a circle of radius r (r in pixel heights), an arc of angle theta, starts and ends on a line of distance r*cos(theta/2) from the origin, reaches a maximum distance r-r*cos(theta/2) from this line and returns. Hence, we must chose theta so that r*(1-cos(theta/2) < z. Theta is clearly less than 90 degrees so 0 < cos(theta/2) < 1, hence 0 < (1 - cos(theta/2)) < 1. Also, r >0, so -- (1-cos(theta/2) < z/r. -cos(theta/2) < z/r - 1. cos(theta/2) > (1 - z/r). Theta/2 < ArcCos[1 - z/r]. Theta < 2*ArcCos[1 - z/r]. Let z = 0.5. cosine, sine, rcosine, rsine, lastRsine, lastRcosine: REAL; z: REAL = 0.5; deltaTheta, theta, lastTheta: REAL; numberOfTimesGoesIn: NAT; cosine _ 1-z/radius; sine _ RealFns.SqRt[1-cosine*cosine]; deltaTheta _ RealFns.ArcTanDeg[sine, cosine]; -- Now find a deltaTheta smaller than this which goes evenly into 45 degrees. numberOfTimesGoesIn _ Real.FixC[45.0/deltaTheta]; deltaTheta _ 45.0/(numberOfTimesGoesIn + 1); lastTheta _ 0; lastRsine _ 0; lastRcosine _ radius; FOR i: NAT IN [1..numberOfTimesGoesIn+1] DO theta _ lastTheta + deltaTheta; rsine _ radius*RealFns.SinDeg[theta]; rcosine _ radius*RealFns.CosDeg[theta]; DrawLine[dc, originX + lastRcosine, originY + lastRsine, originX + rcosine, originY + rsine]; DrawLine[dc, originX + lastRsine, originY + lastRcosine, originX + rsine, originY + rcosine]; DrawLine[dc, originX + lastRcosine, originY - lastRsine, originX + rcosine, originY - rsine]; DrawLine[dc, originX + lastRsine, originY - lastRcosine, originX + rsine, originY - rcosine]; DrawLine[dc, originX - lastRcosine, originY + lastRsine, originX - rcosine, originY + rsine]; DrawLine[dc, originX - lastRsine, originY + lastRcosine, originX - rsine, originY + rcosine]; DrawLine[dc, originX - lastRcosine, originY - lastRsine, originX - rcosine, originY - rsine]; DrawLine[dc, originX - lastRsine, originY - lastRcosine, originX - rsine, originY - rcosine]; lastTheta _ theta; lastRsine _ rsine; lastRcosine _ rcosine; ENDLOOP; }; -- end of Circle DrawLine: PROC [dc: Graphics.Context, fromX, fromY, toX, toY: REAL] = { Graphics.SetCP[dc, fromX, fromY]; Graphics.DrawTo[dc, toX, toY]; }; Cross: PUBLIC PROC [dc: Graphics.Context, originX, originY, length: REAL] = { halfLength: REAL _ length/2.0; DrawLine[dc, originX-halfLength, originY, originX+halfLength, originY]; DrawLine[dc, originX, originY-halfLength, originX, originY+halfLength]; }; centerLine: SV2d.TrigLine _ SVLines2d.CreateEmptyTrigLine[]; LineSandwich: PUBLIC PROC [dc: Graphics.Context, fromX, fromY, toX, toY: REAL] = { leftFirst, leftSecond, rightFirst, rightSecond: Point2d; -- Draw three parallel lines, 2 black with 1 white in between so that the total width is three screen dots. This requires that we calculate the points with are 1 unit from the given central line segment and normal to that line segment. -- find the left and right segments given the center segment SVLines2d.FillTrigLineFromPoints[[fromX, fromY], [toX, toY], centerLine]; leftFirst _ SVLines2d.PointLeftOfTrigLine[1, [fromX, fromY], centerLine]; leftSecond _ SVLines2d.PointLeftOfTrigLine[1, [toX, toY], centerLine]; rightFirst _ SVVector2d.Sum[SVVector2d.Difference[[fromX, fromY], leftFirst], [fromX, fromY]]; rightSecond _ SVVector2d.Sum[SVVector2d.Difference[[toX, toY], leftSecond], [toX, toY]]; -- now draw the left line Graphics.SetColor[dc, GraphicsColor.black]; -- black Graphics.MoveTo[globalSandwich, leftFirst[1], leftFirst[2]]; Graphics.LineTo[globalSandwich, leftSecond[1], leftSecond[2]]; Graphics.DrawStroke[dc, globalSandwich, 1, FALSE, butt]; -- now draw the center line Graphics.SetColor[dc, GraphicsColor.white]; -- white Graphics.MoveTo[globalSandwich, fromX, fromY]; Graphics.LineTo[globalSandwich, toX, toY]; Graphics.DrawStroke[dc, globalSandwich, 1, FALSE, butt]; -- finally, draw the right line Graphics.SetColor[dc, GraphicsColor.black]; -- dark gray Graphics.MoveTo[globalSandwich, rightFirst[1], rightFirst[2]]; Graphics.LineTo[globalSandwich, rightSecond[1], rightSecond[2]]; Graphics.DrawStroke[dc, globalSandwich, 1, FALSE, butt]; }; END. Ęņ˜JšbĪcŪœĪk œcžœžœ1žœ žœ žœHĪnœžœžœ2žœqœÉœ•œ7žœžœ'žœžœoNœ›žœžœžœžœŒžœœŸœžœ0žœOŸœžœžœ2žœžœåŸ œžœžœ0žœAíœ=œšœ- œĒžœ œ- œˆžœ  œ- œŽžœžœ˜(—…—