DIRECTORY Angles2d, GGBasicTypes, GGCircles, GGCoreTypes, GGUtility, Lines2d, RealFns, Vectors2d; GGCirclesImpl: CEDAR PROGRAM IMPORTS Angles2d, Lines2d, Vectors2d, RealFns EXPORTS GGCircles = BEGIN Arc: TYPE = REF ArcObj; ArcObj: TYPE = GGBasicTypes.ArcObj; Circle: TYPE = REF CircleObj; CircleObj: TYPE = GGBasicTypes.CircleObj; Point: TYPE = GGBasicTypes.Point; Edge: TYPE = GGBasicTypes.Edge; Line: TYPE = GGCoreTypes.Line; Vector: TYPE = GGBasicTypes.Vector; CreateEmptyCircle: PUBLIC PROC [] RETURNS [circle: Circle] = { circle _ NEW[CircleObj _ [ origin: [0.0, 0.0], radius: 0.0 ]]; }; CopyCircle: PUBLIC PROC [from: Circle, to: Circle] = { to.origin _ from.origin; to.radius _ from.radius; }; FillCircleFromPointAndRadius: PUBLIC PROC [pt: Point, radius: REAL, circle: Circle] = { circle.origin _ pt; circle.radius _ radius; }; CircleFromPointAndRadius: PUBLIC PROC [pt: Point, radius: REAL] RETURNS [circle: Circle] = { circle _ CreateEmptyCircle[]; FillCircleFromPointAndRadius[pt, radius, circle]; }; CircleFrom3Points: PUBLIC PROC [p0, p1, p2: Point] RETURNS [circle: Circle, linear: BOOL] = { circle _ CreateEmptyCircle[]; linear _ FillCircleFrom3Points[p0, p1, p2, circle]; }; FillCircleFrom3Points: PUBLIC PROC [p0, p1, p2: Point, circle: Circle] RETURNS [linear: BOOL] = { OPEN Vectors2d; IF p0 = p2 THEN { circle.origin _ [(p0.x+p1.x)*0.5, (p0.y+p1.y)*0.5]; -- center of the circle circle.radius _ Distance[circle.origin, p0]; -- vector from center to p0 linear _ FALSE; } ELSE { m1: Point _ [(p0.x+p1.x)*0.5, (p0.y+p1.y)*0.5]; -- midpoint of segment from p0 to p1 v1: Point _ [m1.y-p0.y, p0.x-m1.x]; -- direction vector of perpendicular bisector a1: REAL _ v1.y; b1: REAL _ -v1.x; c1: REAL _ a1*m1.x+b1*m1.y; m2: Point ~ [(p0.x+p2.x)*0.5, (p0.y+p2.y)*0.5]; -- midpoint of segment from p1 to p2 v2: Point ~ [m2.y-p0.y, p0.x-m2.x]; a2: REAL ~ v2.y; b2: REAL ~ -v2.x; c2: REAL ~ a2*m2.x+b2*m2.y; det: REAL ~ a1*b2-a2*b1; IF det = 0 OR ABS[det] < ABS[a1*b2]*0.000005 THEN { circle.origin _ [0.0, 0.0]; circle.radius _ 12.0; -- magic number for debugging linear _ TRUE; } ELSE { circle.origin _ [(c1*b2-c2*b1)/det, (a1*c2-a2*c1)/det]; -- solve the linear system circle.radius _ Distance[circle.origin, p0]; linear _ FALSE; }; }; }; RatherClose: PROC [p1, p2: Point] RETURNS [BOOL] = { epsilon: REAL = 1.0e-5; RETURN[ABS[p1.x - p2.x] < epsilon AND ABS[p1.y - p2.y] < epsilon]; }; CircleMeetsLine: PUBLIC PROC [circle: Circle, line: Line] RETURNS [points: ARRAY [1..2] OF Point, hitCount: [0..2], tangent: BOOL _ FALSE] = { d, magD, b: REAL; p, h: Point; epsilon: REAL = GGUtility.epsilonInPoints; d _ Lines2d.SignedLineDistance[circle.origin, line]; magD _ ABS[d]; SELECT magD - circle.radius FROM > epsilon => hitCount _ 0; IN [-epsilon..epsilon] => { -- tangent. One intersection point. hitCount _ 1; points[1] _ Vectors2d.Sub[circle.origin, Vectors2d.Scale[[-line.s, line.c], d]]; tangent _ TRUE; }; < -epsilon => { -- two intersections hitCount _ 2; p _ Vectors2d.Sub[circle.origin, Vectors2d.Scale[[-line.s, line.c], d]]; b _ RealFns.SqRt[circle.radius*circle.radius - d*d]; h _ Vectors2d.Scale[[line.c, line.s], b]; points[1] _ Vectors2d.Sub[p, h]; points[2] _ Vectors2d.Add[p, h]; }; ENDCASE => ERROR; }; CircleMeetsEdge: PUBLIC PROC [circle: Circle, edge: Edge] RETURNS [points: ARRAY [1..2] OF Point, hitCount: [0..2], tangent: BOOL] = { line: Line _ edge.line; testPoints: ARRAY [1..2] OF Point; testCount: [0..2]; [testPoints, testCount, tangent] _ CircleMeetsLine[circle, line]; hitCount _ 0; FOR i: NAT IN [1..testCount] DO IF Lines2d.OnEdge[testPoints[i], edge] THEN { hitCount _ hitCount + 1; points[hitCount] _ testPoints[i]; }; ENDLOOP; }; CircleMeetsCircle: PUBLIC PROC [circle1, circle2: Circle] RETURNS [points: ARRAY [1..2] OF Point, hitCount: [0..2], tangent: BOOL _ FALSE] = { o1ToO2, o1ToO2Hat: Vector; epsilon: REAL = GGUtility.epsilonInPoints; magO1ToO2, outerTangent, innerTangent: REAL; IF RatherClose[circle1.origin, circle2.origin] THEN { -- concentric circles hitCount _ 0; points[1] _ points[2] _ [0.0, 0.0]; -- avoids compiler warnings RETURN; }; o1ToO2 _ Vectors2d.Sub[circle2.origin, circle1.origin]; magO1ToO2 _ Vectors2d.Magnitude[o1ToO2]; outerTangent _ circle1.radius + circle2.radius; innerTangent _ ABS[circle1.radius - circle2.radius]; SELECT magO1ToO2 FROM > outerTangent+epsilon => hitCount _ 0; -- circles far apart IN [outerTangent-epsilon .. outerTangent+epsilon] => { -- circles just touch as shown hitCount _ 1; tangent _ TRUE; o1ToO2Hat _ Vectors2d.Scale[o1ToO2, 1.0/magO1ToO2]; points[1] _ Vectors2d.Add[circle1.origin, Vectors2d.Scale[o1ToO2Hat, circle1.radius]]; }; IN (innerTangent+epsilon .. outerTangent-epsilon) => { p: Point; normal: Vector; s, h, m: REAL; b: REAL _ circle1.radius; a: REAL _ circle2.radius; hitCount _ 2; o1ToO2Hat _ Vectors2d.Scale[o1ToO2, 1.0/magO1ToO2]; s _ 0.5*(b + a + magO1ToO2); h _ 2.0*RealFns.SqRt[s*(s-magO1ToO2)*(s-b)*(s-a)]/magO1ToO2; IF b > a THEN { m _ RealFns.SqRt[b*b - h*h]; p _ Vectors2d.Add[circle1.origin, Vectors2d.Scale[o1ToO2Hat, m]]; } ELSE { m _ RealFns.SqRt[a*a - h*h]; p _ Vectors2d.Sub[circle2.origin, Vectors2d.Scale[o1ToO2Hat, m]]; }; normal _ [-h*o1ToO2Hat.y, h*o1ToO2Hat.x]; points[1] _ Vectors2d.Sub[p, normal]; points[2] _ Vectors2d.Add[p, normal]; }; IN [innerTangent-epsilon .. innerTangent+epsilon] => { hitCount _ 1; tangent _ TRUE; IF circle1.radius > circle2.radius THEN { o1ToO2Hat _ Vectors2d.Scale[o1ToO2, 1.0/magO1ToO2]; points[1] _ Vectors2d.Add[circle1.origin, Vectors2d.Scale[o1ToO2Hat, circle1.radius]]; } ELSE { o1ToO2Hat _ Vectors2d.Scale[o1ToO2, -1.0/magO1ToO2]; points[1] _ Vectors2d.Add[circle2.origin, Vectors2d.Scale[o1ToO2Hat, circle2.radius]]; }; }; < innerTangent-epsilon => { hitCount _ 0; }; ENDCASE => ERROR; }; CircleMeetsArc: PUBLIC PROC [circle: Circle, arc: Arc] RETURNS [points: ARRAY [1..2] OF Point, hitCount: [0..2], tangent: BOOL] = { IF arc.edge # NIL THEN [points, hitCount, tangent] _ CircleMeetsEdge[circle, arc.edge] ELSE { pts: ARRAY [1..2] OF Point; hCount: [0..2]; [pts, hCount, tangent] _ CircleMeetsCircle[circle, arc.circle]; hitCount _ 0; FOR i: NAT IN [1..hCount] DO IF OnArc[pts[i], arc] THEN { hitCount _ hitCount + 1; points[hitCount] _ pts[i]; }; ENDLOOP; }; }; SignedCircleDistance: PUBLIC PROC [pt: Point, circle: Circle] RETURNS [d: REAL] = { originToPoint: REAL; originToPoint _ Vectors2d.Magnitude[Vectors2d.Sub[pt, circle.origin]]; d _ originToPoint - circle.radius; }; CircleDistance: PUBLIC PROC [pt: Point, circle: Circle] RETURNS [d: REAL] = { d _ ABS[SignedCircleDistance[pt, circle]]; }; PointProjectedOntoCircle: PUBLIC PROC [pt: Point, circle: Circle] RETURNS [projectedPt: Point] = { epsilon: REAL = 1.0e-5; originToPoint: Vector; magOriginToPoint: REAL; originToPoint _ Vectors2d.Sub[pt, circle.origin]; magOriginToPoint _ Vectors2d.Magnitude[originToPoint]; IF magOriginToPoint < epsilon THEN { projectedPt _ [circle.origin.x + circle.radius, circle.origin.y]; RETURN; }; projectedPt _ Vectors2d.Add[circle.origin, Vectors2d.Scale[originToPoint, circle.radius/magOriginToPoint]]; }; PointIsInCircle: PUBLIC PROC [pt: Point, circle: Circle] RETURNS [BOOL] = { deltaX, deltaY: REAL; deltaX _ pt.x - circle.origin.x; deltaY _ pt.y - circle.origin.y; RETURN[deltaX*deltaX+deltaY*deltaY < circle.radius*circle.radius]; }; CreateArc: PUBLIC PROC [v0, v1, v2: Point] RETURNS [arc: Arc] = { arc _ CreateEmptyArc[]; FillArc[v0, v1, v2, arc]; }; CreateEmptyArc: PUBLIC PROC [] RETURNS [arc: Arc] = { arc _ NEW[ArcObj _ [circle: CreateEmptyCircle[], ccw: FALSE, p0: [0.0,0.0], p2: [0.0,0.0], theta0: 0.0, deltaTheta: 0.0]]; }; ReverseArc: PUBLIC PROC [arc: Arc] = { arc.ccw _ NOT arc.ccw; IF arc.edge # NIL THEN arc.edge.startIsFirst _ NOT arc.edge.startIsFirst; -- This should be a call to Lines2d.ReverseEdge, but there is no Lines2d.ReverseEdge yet. }; FillArc: PUBLIC PROC [v0, v1, v2: Point, arc: Arc] = { theta0, theta1, theta2, deltaTheta: REAL; vector0, vector1, vector2: Vector; linear: BOOL; linear _ FillCircleFrom3Points[v0, v1, v2, arc.circle]; IF linear THEN { arc^ _ [circle: arc.circle, ccw: TRUE, p0: v0, p2: v2, theta0: 0.0, deltaTheta: 0.0, edge: Lines2d.CreateEdge[v0, v2]]; } ELSE { vector0 _ Vectors2d.Sub[v0, arc.circle.origin]; theta0 _ Vectors2d.AngleFromVector[vector0]; vector1 _ Vectors2d.Sub[v1, arc.circle.origin]; theta1 _ Vectors2d.AngleFromVector[vector1]; vector2 _ Vectors2d.Sub[v2, arc.circle.origin]; theta2 _ Vectors2d.AngleFromVector[vector2]; IF theta0 = theta2 THEN { deltaTheta _ 360.0; arc^ _ [circle: arc.circle, ccw: TRUE, p0: v0, p2: v2, theta0: theta0, deltaTheta: deltaTheta, edge: NIL]; } ELSE { IF Angles2d.IsInCCWInterval[theta1, theta0, theta2] THEN { -- CCW arc deltaTheta _ Angles2d.CounterClockwiseAngle[theta0, theta2]; arc^ _ [circle: arc.circle, ccw: TRUE, p0: v0, p2: v2, theta0: theta0, deltaTheta: deltaTheta, edge: NIL]; } ELSE { deltaTheta _ Angles2d.CounterClockwiseAngle[theta2, theta0]; arc^ _ [circle: arc.circle, ccw: FALSE, p0: v2, p2: v0, theta0: theta2, deltaTheta: deltaTheta, edge: NIL]; }; }; }; }; CopyArc: PUBLIC PROC [from: Arc, to: Arc] = { CopyCircle[from.circle, to.circle]; to.ccw _ from.ccw; to.p0 _ from.p0; to.p2 _ from.p2; to.theta0 _ from.theta0; to.deltaTheta _ from.deltaTheta; IF from.edge # NIL THEN { to.edge _ Lines2d.CreateEmptyEdge[]; Lines2d.CopyEdge[from: from.edge, to: to.edge]; }; }; CirclePointOnArc: PUBLIC PROC [pt: Point, arc: Arc] RETURNS [BOOL] = { direction: Vector _ Vectors2d.Sub[pt, arc.circle.origin]; angle: REAL _ Vectors2d.AngleFromVector[direction]; IF arc.edge # NIL THEN RETURN[Lines2d.LinePointOnEdge[pt, arc.edge]]; RETURN[Angles2d.IsInCCWInterval2[angle, arc.theta0, arc.deltaTheta]]; }; ArcMeetsLine: PUBLIC PROC [arc: Arc, line: Line] RETURNS [points: ARRAY [1..2] OF Point, hitCount: [0..2], tangent: BOOL _ FALSE] = { IF arc.edge # NIL THEN { noHit: BOOL; [points[1], noHit] _ Lines2d.LineMeetsEdge[line, arc.edge]; hitCount _ IF noHit THEN 0 ELSE 1; } ELSE { pts: ARRAY [1..2] OF Point; hCount: [0..2]; [pts, hCount, tangent] _ CircleMeetsLine[arc.circle, line]; hitCount _ 0; FOR i: NAT IN [1..hCount] DO IF OnArc[pts[i], arc] THEN { hitCount _ hitCount + 1; points[hitCount] _ pts[i]; }; ENDLOOP; }; }; ArcMeetsEdge: PUBLIC PROC [arc: Arc, edge: Edge] RETURNS [points: ARRAY [1..2] OF Point, hitCount: [0..2], tangent: BOOL _ FALSE] = { IF arc.edge # NIL THEN { noHit: BOOL; [points[1], noHit] _ Lines2d.EdgeMeetsEdge[edge, arc.edge]; hitCount _ IF noHit THEN 0 ELSE 1; } ELSE { pts: ARRAY [1..2] OF Point; hCount: [0..2]; [pts, hCount, tangent] _ CircleMeetsEdge[arc.circle, edge]; hitCount _ 0; FOR i: NAT IN [1..hCount] DO IF OnArc[pts[i], arc] THEN { hitCount _ hitCount + 1; points[hitCount] _ pts[i]; }; ENDLOOP; }; }; ArcMeetsArc: PUBLIC PROC [arc1, arc2: Arc] RETURNS [points: ARRAY [1..2] OF Point, hitCount: [0..2], tangent: BOOL] = { IF arc1.edge # NIL THEN [points, hitCount, tangent] _ ArcMeetsEdge[arc2, arc1.edge] ELSE { pts: ARRAY [1..2] OF Point; hCount: [0..2]; [pts, hCount, tangent] _ CircleMeetsArc[arc1.circle, arc2]; hitCount _ 0; FOR i: NAT IN [1..hCount] DO IF OnArc[pts[i], arc1] THEN { hitCount _ hitCount + 1; points[hitCount] _ pts[i]; }; ENDLOOP; }; }; NearestEndpoint: PUBLIC PROC [pt: Point, arc: Arc] RETURNS [endpoint: Point] = { IF arc.edge # NIL THEN RETURN[Lines2d.NearestEndpoint[pt, arc.edge]]; BEGIN IF ABS[pt.x-arc.p0.x] <= ABS[pt.x-arc.p2.x] THEN { IF ABS[pt.y-arc.p0.y] <= ABS[pt.y-arc.p2.y] THEN RETURN[arc.p0] ELSE GOTO DoMath } ELSE IF ABS[pt.y-arc.p0.y] > ABS[pt.y-arc.p2.y] THEN RETURN[arc.p2] ELSE GOTO DoMath; EXITS DoMath => IF Vectors2d.DistanceSquared[pt, arc.p0] < Vectors2d.DistanceSquared[pt, arc.p2] THEN endpoint _ arc.p0 ELSE endpoint _ arc.p2; END; }; DistanceSquaredToNearestEndpoint: PUBLIC PROC [pt: Point, arc: Arc] RETURNS [distanceSquared: REAL] = { distance2ToPLo, distance2ToPHi: REAL; distance2ToPLo _ Vectors2d.DistanceSquared[pt, arc.p0]; distance2ToPHi _ Vectors2d.DistanceSquared[pt, arc.p2]; RETURN[MIN[distance2ToPLo, distance2ToPHi]]; }; NearestPointOnArc: PUBLIC PROC [pt: Point, arc: Arc] RETURNS [onArc: Point] = { projectedPt: Point; IF arc.edge # NIL THEN RETURN[Lines2d.NearestPointOnEdge[pt, arc.edge]]; projectedPt _ PointProjectedOntoCircle[pt, arc.circle]; IF CirclePointOnArc[projectedPt, arc] THEN onArc _ projectedPt ELSE onArc _ NearestEndpoint[pt, arc]; }; DistancePointToArc: PUBLIC PROC [pt: Point, arc: Arc] RETURNS [distance: REAL] = { projectedPt, nearEndpoint: Point; IF arc.edge # NIL THEN RETURN[Lines2d.DistancePointToEdge[pt, arc.edge]]; projectedPt _ PointProjectedOntoCircle[pt, arc.circle]; IF CirclePointOnArc[projectedPt, arc] THEN distance _ ABS[CircleDistance[pt, arc.circle]] ELSE { nearEndpoint _ NearestEndpoint[pt, arc]; distance _ Vectors2d.Distance[pt, nearEndpoint]; }; }; DistanceSquaredPointToArc: PUBLIC PROC [pt: Point, arc: Arc] RETURNS [distanceSquared: REAL] = { projectedPt: Point; IF arc.edge # NIL THEN RETURN[Lines2d.DistanceSquaredPointToEdge[pt, arc.edge]]; projectedPt _ PointProjectedOntoCircle[pt, arc.circle]; IF CirclePointOnArc[projectedPt, arc] THEN {distanceSquared _ CircleDistance[pt, arc.circle]; distanceSquared _ distanceSquared*distanceSquared} ELSE distanceSquared _ DistanceSquaredToNearestEndpoint[pt, arc]; }; OnArc: PUBLIC PROC [pt: Point, arc: Arc] RETURNS [BOOL] = { d2: REAL; epsilon: REAL = 1.0e-5; d2 _ DistanceSquaredPointToArc[pt, arc]; RETURN[d2 < epsilon]; }; END. GGCirclesImpl.mesa Author: Eric Bier on June 4, 1985 4:58:33 pm PDT Last edited by Bier on July 16, 1987 1:58:44 pm PDT Contents: Routines for finding the intersections of various types of circles, lines, and points. Pier, September 18, 1990 11:24 am PDT Bier, May 8, 1989 2:14:49 pm PDT Circles Find the perpendicular bisectors of [p0, p1] and [p1, p2]. Their intersection is the center of circle. The distance of p0 or p1 or p2 from the center is the radius. a1*x + b1*y = c1 is the equation of the first perpendicular bisector a2*x + b2*y = c2 is the equation of the second perpendicular bisector These lines are now two simultaneous linear equations. The determinant is: Line: cy -sx - d = 0. (f(x) = 0) Circle: x2 + y2 = r2. (g(x) = 0) [Artwork node; type 'ArtworkInterpress on' to command tool] The two circles overlap. We expect two roots. In the picture below, point C is one of the circle intersection points. Segment AB is the segment O1O2 in the picture above. We wish to find the altitude h of the triangle. b = r1 and a = r2. From Heron's formula for the area of a triangle, area K = sqrt(s(s-a)(s-b)(s-c)), where s = (a+b+ c)/2. We also know that the area K = 0.5ch. So h = 2K/c. This gives us the y coordinate of the intersection points. The x coordinate is the point where the altitude hits the base, which we get from the Pythagorean Theorem. [Artwork node; type 'ArtworkInterpress on' to command tool] We drop a normal from the point onto the circle and find where it hits. Arcs Invariants: arc.deltaTheta is always a positive, counterclockwise angle. All arcs can be thought of as counterclockwise if you start at the proper end. arc.theta0 always correpondes to arc.p0. arc.ccw says whether the arc is really counterclockwise or not. Assumes pt is on arc.circle. Is it on arc? Look for a winner with the infinity norm first. If that fails, use the 2 norm. The nearest point on arc.circle to pt, if the nearest point is on arc. Otherwise, the nearest endpoint. Distance[pt, NearestPointOnArc[pt, arc]]. Ê4˜Icode™KšÏnœ'Ïk™0Kšœ3™3šœY™aKšœ%™%K™ —K˜šž ˜ JšœW˜W—K˜š œžœž˜Kšžœ&˜-Kšžœ ž˜—˜Kšœžœžœ˜Kšœžœ˜#Kšœžœžœ ˜Kšœ žœ˜)Kšœžœ˜!Kšœžœ˜Kšœžœ˜šœžœ˜#K˜——™K˜—šœžœžœžœ˜>šœ žœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜K˜——š œžœžœ ˜7Kšœ˜Kšœ˜Kšœ˜—K˜šœžœžœžœ˜XKšœ˜Kšœ˜Kšœ˜K˜—š œžœžœžœžœ˜]Kšœ˜Kšœ1˜1Kšœ˜K˜—š œžœžœžœžœ˜]Kšœ˜Kšœ3˜3Kšœ˜K˜—š œžœžœ&žœ žœ˜bKšœ¦™¦Kšžœ ˜šžœ žœ˜Kšœ4Ïc˜KKšœ-Ÿ˜HKšœ žœ˜Kšœ˜—šžœ˜Kšœ0Ÿ$˜TKšœ$Ÿ-˜QKšœžœ˜Kšœžœ ˜šœžœ˜K™D—Kšœ1Ÿ$˜UKšœ#˜#Kšœžœ˜Kšœžœ ˜šœžœ˜KšœE™EKšÏbK™K—Kšœžœ˜š žœ žœžœžœžœ˜3Kšœ˜KšœŸ˜3Kšœ žœ˜K˜—šžœ˜Kšœ8Ÿ˜RKšœ,˜,Kšœ žœ˜K˜—K˜—K˜K˜—š œžœžœžœ˜4Kšœ žœ ˜Kšžœžœžœžœ˜BK˜K˜—šœžœžœžœ žœžœ#žœžœ˜Kšœ œ™ Kš œ Ïuœ¡œ¡œ œ™ Kšœ žœ˜K˜ Kšœ žœ˜*Kšœ4˜4Kšœžœ˜Kšžœž˜ Kšœ˜šžœŸ$˜@Kšœ ˜ KšœP˜PKšœ žœ˜K˜—šœŸ˜$Kšœ ˜ KšœH˜HKšœ4˜4Kšœ)˜)Kšœ ˜ Kšœ ˜ K˜—Kšžœžœ˜Kšœ˜K˜—šœžœžœžœ žœžœ#žœ˜‡Kšœ˜Kšœ žœžœ˜"K˜KšœA˜AKšœ ˜ šžœžœžœž˜šžœ%žœ˜-Kšœ˜Kšœ!˜!K˜—Kšžœ˜—K˜K˜—šœžœžœžœ žœžœ#žœžœ˜Icaption˜Lšœ žœ˜*Kšœ'žœ˜,šžœ-žœŸ˜KKšœ ˜ Kšœ$Ÿ˜?Kšžœ˜K˜—Kšœ7˜7Kšœ(˜(Kšœ/˜/Kšœžœ"˜4Icenter• InterpressÙInterpress/Xerox/3.0  f j k j¡¥“ÄWB ¤ ¨  `#¡£§G ¢ ¨Ä™ÄþS ¢ ¨¡¡¨ÄWB ¤ ¨ r j¡¥“ÄWB ¤ ¨¡¡¨¡¯“¡¡¨¢°“ ¡¨Þ™HÞ¡“¡¡¡¡™¡¡¨Þ™HÞ¡“¡¸¡¯“¡¯“¡¡¨¢°“ ¡¨H™€H¡“¡¡¡¡™¡¡¨H™€H¡“¡¸¡¯“¡¯“¡¡¨¢°“ÄšHÄ¡¹¡¯“¡¯“¡¡¨¢°“Äs Äa‘ºd¡¹¡¯“ÅXeroxÅ PressFontsÅ Helvetica-mrr£¡ “ª ¤ ” •  —Ä:ƒ/ŠÁr1–  —e ŠÁr2–  —ŠÁO1–  —k ŠÁO2–¡¯“¡¡¨¢°“d¡¹¡¯“ k é k g•Artwork Interpress•Bounds:0.0 mm xmin 0.0 mm ymin 67.73333 mm xmax 46.21388 mm ymax –G49.03611 mm topLeading 49.03611 mm topIndent 1.411111 mm bottomLeading šœ=™=Kšžœ ž˜Kšœ(Ÿ˜<šžœ5Ÿ˜UKšœ ˜ Kšœ žœ˜Kšœ3˜3KšœV˜VK˜—šžœ4˜6Kšœžœžœ¡™¸M–ŽInterpress/Xerox/3.0  f j k j¡¥“ÄWB ¤ ¨  à~¡£ß» ¢ ¨  ¡ ¢ ¨¡¡¨ÄWB ¤ ¨ r j¡¥“ÄWB ¤ ¨¡¡¨¡¯“¡¡¨¢°“x›ðL¡¹¡¯“¡¡¨¢°“ðL…›¡¹¡¯“¡¡¨¢°“…›x›¡¹¡¯“ÅXeroxÅ PressFontsÅ Helvetica-mrr£¡ “ª ¤ ” •  —@þŠÁa–  —©úŠÁb–  —Ä>_0ÄÓ?ãŠÁc–¡¯“¡¡¨¢°“ð›ðL¡¹¡¯“  —çÄŠÁh–  —¸©ŠÁm–  —rŠÁA–  —Ä0G”ŠÁB–  —ÄQß?SŠÁC– k é k g– Interpress–:0.0 mm xmin 0.0 mm ymin 112.8889 mm xmax 78.31667 mm ymax –G81.13889 mm topLeading 81.13889 mm topIndent 1.411111 mm bottomLeading šœ=™=K˜ K˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœ ˜ Kšœ3˜3Kšœ˜Kšœ<˜<šžœžœ˜Kšœ˜KšœA˜AK˜—šžœ˜Kšœ˜KšœA˜AK˜—Kšœ)˜)Kšœ%˜%Kšœ%˜%K˜—šžœ4˜6Kšœ ˜ Kšœ žœ˜šžœ!žœ˜)Kšœ3˜3KšœV˜VK˜—šžœ˜Kšœ4˜4KšœV˜VK˜—K˜—šœ˜Kšœ ˜ K˜—Kšžœžœ˜Kšœ˜K˜—šœžœžœžœ žœžœ#žœ˜ƒKšžœ žœžœ@˜Všžœ˜Kšœžœžœ˜Kšœ˜Kšœ?˜?Kšœ ˜ šžœžœžœ ž˜šžœžœ˜Kšœ˜Kšœ˜K˜—Kšžœ˜—K˜—K˜K˜—š œžœžœžœžœ˜TKšœžœ˜KšœF˜FKšœ"˜"Kšœ˜K˜—š œžœžœžœžœ˜NKšœžœ#˜*Kšœ˜K˜—šœžœžœžœ˜cKšœG™GKšœ žœ ˜K˜Kšœžœ˜Kšœ1˜1Kšœ6˜6šžœžœ˜$KšœA˜AKšžœ˜K˜—Kšœk˜kKšœ˜—š œžœžœžœžœ˜LKšœžœ˜Kšœ ˜ Kšœ ˜ Kšžœ<˜BK˜K˜—™K˜—š œžœžœžœ˜BKšœ˜Kšœ˜Kšœ˜K˜—šœžœžœžœ˜5Kšœžœ-žœ?˜zKšœ˜K˜—š œžœžœ˜&Kšœƒ™ƒKšœ žœ ˜Kš žœ žœžœžœŸY˜£K˜K˜—šœžœžœ#˜7Kšœ$žœ˜)Kšœ"˜"Kšœžœ˜ Kšœ7˜7šžœžœ˜Kšœ!žœR˜wK˜—šžœ˜Kšœ/˜/Kšœ,˜,Kšœ/˜/Kšœ,˜,Kšœ/˜/Kšœ,˜,šžœžœ˜Kšœ˜Kšœ!žœ@žœ˜jK˜—šžœ˜šžœ2žœŸ ˜EKšœ<˜Kšžœžœ˜—šž˜šœ ˜ KšžœN˜PKšžœ˜Kšžœ˜——Kšžœ˜Kšœ˜K˜—š œžœžœžœžœ˜gKšœ žœ˜%Kšœ7˜7Kšœ7˜7Kšžœžœ"˜,Kšœ˜K˜—šœžœžœžœ˜OKšœh™hKšœ˜Kšžœ žœžœžœ+˜HKšœ7˜7Kšžœ$žœ˜>Kšžœ"˜&Kšœ˜K˜—š œžœžœžœ žœ˜SKšœ)™)Kšœ!˜!Kšžœ žœžœžœ,˜IKšœ7˜7Kšžœ$žœ žœ ˜Yšžœ˜Kšœ(˜(Kšœ0˜0Kšœ˜—Kšœ˜K˜—š œžœžœžœžœ˜aKšœ˜Kšžœ žœžœžœ3˜PKšœ7˜7Kšžœ#˜%Kšžœ3˜7Kšœ3˜3Kšžœ=˜AKšœ˜K˜—š œžœžœžœžœ˜;Kšœ¡œžœ˜ Kšœ žœ ˜Kšœ¡œ&˜(Kšžœ¡œ ˜K˜—K™Kšžœ˜K˜K˜—…—4®Qè