DIRECTORY
GGAngle, GGBasicTypes, GGCircles, GGLines, GGUtility, GGVector, RealFns;

GGCirclesImpl: CEDAR PROGRAM
IMPORTS GGAngle, GGLines, GGVector, 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 = GGBasicTypes.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 GGVector;
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 _ GGLines.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] _ GGVector.Sub[circle.origin, GGVector.Scale[[-line.s, line.c], d]];
tangent _ TRUE;
};
< -epsilon => { -- two intersections
hitCount _ 2;
p _ GGVector.Sub[circle.origin, GGVector.Scale[[-line.s, line.c], d]];
b _ RealFns.SqRt[circle.radius*circle.radius - d*d];
h _ GGVector.Scale[[line.c, line.s], b];
points[1] _ GGVector.Sub[p, h];
points[2] _ GGVector.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 GGLines.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;
RETURN;
};
o1ToO2 _ GGVector.Sub[circle2.origin, circle1.origin];
magO1ToO2 _ GGVector.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 _ GGVector.Scale[o1ToO2, 1.0/magO1ToO2];
points[1] _ GGVector.Add[circle1.origin, GGVector.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 _ GGVector.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 _ GGVector.Add[circle1.origin, GGVector.Scale[o1ToO2Hat, m]];
}
ELSE {
m _ RealFns.SqRt[a*a - h*h];
p _ GGVector.Sub[circle2.origin, GGVector.Scale[o1ToO2Hat, m]];
};
normal _ [-h*o1ToO2Hat.y, h*o1ToO2Hat.x];
points[1] _ GGVector.Sub[p, normal];
points[2] _ GGVector.Add[p, normal];
};
IN [innerTangent-epsilon .. innerTangent+epsilon] => {
hitCount _ 1;
tangent _ TRUE;
IF circle1.radius > circle2.radius THEN {
o1ToO2Hat _ GGVector.Scale[o1ToO2, 1.0/magO1ToO2];
points[1] _ GGVector.Add[circle1.origin, GGVector.Scale[o1ToO2Hat, circle1.radius]];
}
ELSE {
o1ToO2Hat _ GGVector.Scale[o1ToO2, -1.0/magO1ToO2];
points[1] _ GGVector.Add[circle2.origin, GGVector.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;
};
};

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] _ GGLines.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] _ GGLines.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;
};
};

SignedCircleDistance: PUBLIC PROC  [pt: Point, circle: Circle] RETURNS [d: REAL] = {
originToPoint: REAL;
originToPoint _ GGVector.Magnitude[GGVector.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 _ GGVector.Sub[pt, circle.origin];
magOriginToPoint _ GGVector.Magnitude[originToPoint];
IF magOriginToPoint < epsilon THEN {
projectedPt _ [circle.origin.x + circle.radius, circle.origin.y];
RETURN;
};
projectedPt _ GGVector.Add[circle.origin, GGVector.Scale[originToPoint, circle.radius/magOriginToPoint]];
};

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]];
};
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: GGLines.CreateEdge[v0, v2]];
}
ELSE {
vector0 _ GGVector.Sub[v0, arc.circle.origin];
theta0 _ GGVector.AngleFromVector[vector0];
vector1 _ GGVector.Sub[v1, arc.circle.origin];
theta1 _ GGVector.AngleFromVector[vector1];
vector2 _ GGVector.Sub[v2, arc.circle.origin];
theta2 _ GGVector.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 GGAngle.IsInCCWInterval[theta1, theta0, theta2] THEN { -- CCW arc
deltaTheta _ GGAngle.CounterClockwiseAngle[theta0, theta2];
arc^ _ [circle: arc.circle, ccw: TRUE, p0: v0, p2: v2, theta0: theta0, deltaTheta: deltaTheta, edge: NIL];
}
ELSE {
deltaTheta _ GGAngle.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 _ GGLines.CreateEmptyEdge[];
GGLines.CopyEdge[from: from.edge, to: to.edge];
};
};
CirclePointOnArc: PUBLIC PROC  [pt: Point, arc: Arc] RETURNS [BOOL] = {
direction: Vector _ GGVector.Sub[pt, arc.circle.origin];
angle: REAL _ GGVector.AngleFromVector[direction];
IF arc.edge # NIL THEN RETURN[GGLines.LinePointOnEdge[pt, arc.edge]];
RETURN[GGAngle.IsInCCWInterval2[angle, arc.theta0, arc.deltaTheta]];
};
NearestEndpoint: PUBLIC PROC  [pt: Point, arc: Arc] RETURNS [endpoint: Point] = {
IF arc.edge # NIL THEN RETURN[GGLines.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 GGVector.DistanceSquared[pt, arc.p0] < GGVector.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 _ GGVector.DistanceSquared[pt, arc.p0];
distance2ToPHi _ GGVector.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[GGLines.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[GGLines.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 _ GGVector.Distance[pt, nearEndpoint];
};
};
DistanceSquaredPointToArc: PUBLIC PROC  [pt: Point, arc: Arc] RETURNS [distanceSquared: REAL] = {
projectedPt: Point;
IF arc.edge # NIL THEN RETURN[GGLines.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 January 26, 1987 11:02:16 pm PST
Contents:  Routines for finding the intersections of various types of circles, lines, and points.
Pier, May 30, 1986 5:24:52 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
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]].

�Êt��˜�Icode™Kšœ0™0Kšœ7™7šœa™aK™!—K˜�šÏk	˜	KšœH˜H—K˜�šœœ˜Kšœ$˜+Kšœ˜—Kš˜˜�Kšœœœ˜Kšœœ˜#Kšœœœ˜Kšœœ˜)Kšœœ˜!Kšœœ˜Kšœœ˜šœœ˜#K˜�——K™K˜�šÏnœœœœ˜>šœ	œ˜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˜�—K˜�šžœœœœ˜4Kšœ	œ
˜Kšœœœœ˜BK˜K˜�—K˜�šžœœœœ
œœ#œ˜Kšœ œ™ Kš	œ	Ïuœ¡œ¡œ œ™ Kšœœ˜K˜Kšœ	œ˜*Kšœ4˜4Kšœœ˜Kšœ˜ Kšœ˜šœŸ$˜@Kšœ
˜
KšœN˜NKšœ
œ˜K˜—šœŸ˜$Kšœ
˜
KšœF˜FKšœ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šœ6˜6Kšœ'˜'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šœ2˜2KšœT˜TK˜—šœ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šœ2˜2Kšœ˜Kšœ<˜<šœœ˜Kšœ˜Kšœ?˜?K˜—šœ˜Kšœ˜Kšœ?˜?K˜—Kšœ)˜)Kšœ$˜$Kšœ$˜$K˜—šœ4˜6Kšœ
˜
Kšœ
œ˜šœ!œ˜)Kšœ2˜2KšœT˜TK˜—šœ˜Kšœ3˜3KšœT˜TK˜—K˜—šœ˜Kšœ
˜
K˜—Kšœœ˜Kšœ˜—K˜�šžœœœœ
œœ#œ˜ƒKšœœœ@˜Všœ˜Kšœœœ˜Kšœ˜Kšœ?˜?Kšœ
˜
šœœœ
˜šœœ˜Kšœ˜Kšœ˜K˜—Kšœ˜—K˜—K˜K˜�—šžœœœœ
œœ#œ˜…šœœœ˜Kšœœ˜Kšœ;˜;Kšœœœœ˜"K˜—šœ˜Kšœœœ˜Kšœ˜Kšœ;˜;Kšœ
˜
šœœœ
˜šœœ˜Kšœ˜Kšœ˜K˜—Kšœ˜—K˜—K˜K˜�—šžœœœœ
œœ#œ˜…šœœœ˜Kšœœ˜Kšœ;˜;Kšœœœœ˜"K˜—šœ˜Kšœœœ˜Kšœ˜Kšœ;˜;Kšœ
˜
šœœœ
˜šœœ˜Kšœ˜Kšœ˜K˜—Kšœ˜—K˜—K˜K˜�—šžœœœœ
œœ#œ˜wKšœ
œœ<˜Sšœ˜Kšœœœ˜Kšœ˜Kšœ;˜;Kšœ
˜
šœœœ
˜šœœ˜Kšœ˜Kšœ˜K˜—Kšœ˜—K˜—K˜—K˜�š
žœœœœœ˜TKšœœ˜KšœD˜DKšœ"˜"Kšœ˜—š
žœœœœœ˜NKšœœ#˜*Kšœ˜—šžœœœœ˜cKšœG™GKšœ	œ
˜K˜Kšœœ˜Kšœ0˜0Kšœ5˜5šœœ˜$KšœA˜AKšœ˜K˜—Kšœi˜iKšœ˜—K™�K™K˜�šž	œœœœ˜BKšœ˜Kšœ˜Kšœ˜K˜�—šžœœœœ˜5Kšœœ-œ?˜zKšœ˜—šžœœœ#˜7Kšœ$œ˜)Kšœ"˜"Kšœœ˜
Kšœ7˜7šœœ˜Kšœ!œR˜wK˜—šœ˜Kšœ.˜.Kšœ+˜+Kšœ.˜.Kšœ+˜+Kšœ.˜.Kšœ+˜+šœ˜Kšœ˜Kšœ!œ@œ˜jK˜—šœ˜šœ1œŸ
˜DKšœ;˜;Kšœ!œ@œ˜jK˜—šœ˜Kšœ;˜;Kšœ!œ@œ˜kK˜—K˜—K˜—Kšœ˜K˜�—šžœœœ˜-K˜#Kšœ˜Kšœ˜K˜K˜Kšœ ˜ šœ
œœ˜Kšœ$˜$Kšœ/˜/K˜—Kšœ˜—š
žœœœœœ˜GKšœ+™+Kšœ8˜8Kšœœ'˜2Kšœœœœ(˜EKšœ>˜DKšœ˜—šžœœœœ˜QKšœO™OKšœœœœ(˜EKš˜šœœœ˜2Kš
œœœœœ˜?Kšœœ˜K˜—š˜Kš
œœœœœ˜>Kšœœ˜—š˜šœ	˜	KšœL˜NKšœ˜Kšœ˜——Kšœ˜Kšœ˜K˜�—š
ž œœœœœ˜gKšœ œ˜%Kšœ6˜6Kšœ6˜6Kšœœ"˜,Kšœ˜K˜�—šžœœœœ˜OKšœh™hKšœ˜Kšœœœœ+˜HKšœ7˜7Kšœ$œ˜>Kšœ"˜&Kšœ˜K˜�—š
žœœœœœ˜SKšœ)™)Kšœ!˜!Kšœœœœ,˜IKšœ7˜7Kšœ$œœ ˜Yšœ˜Kšœ(˜(Kšœ/˜/Kšœ˜—Kšœ˜—š
žœœœœœ˜aKšœ˜Kšœœœœ3˜PKšœ7˜7Kšœ#˜%Kšœ3˜7Kšœ3˜3Kšœ=˜AKšœ˜K˜�—š
žœœœœœ˜;Kšœ¡œœ˜	Kšœ	œ
˜Kšœ¡œ&˜(Kšœ¡œ˜K˜—K˜�K™�Kšœ˜K˜�K˜�—�…—����2V��M¬��