A bracket carries two pulleys. Set up coordinates with the centre of the large pulley at the origin C; the centre of the small pulley is at D, 31.5 mm to the right and 13.6 mm above it. The large pulley is 15.9 mm across and the small one is 7.7 mm across. A straight belt run passes over the tops of both pulleys, touching the large one at T and the small one at V. The belt does not cross over between the two pulleys.

Report every point as [x, y] in the datum frame described in the text, and every circle as {centre_label: radius}. Give at least 4 decimal places: a stated fact counts as satisfied only when its residual is below 5e-3 mm.

"""Belt run tangent to two pulleys

Oracle formalization for cad_t1_cad_belt_tangent_0045. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(46)

C, D, T, V = scene.add.points(["C", "D", "T", "V"])

scene.constraint.eq(C.x, 0, description="datum: C is the origin, the centre of the large pulley (x)")
scene.constraint.eq(C.y, 0, description="datum: C is the origin, the centre of the large pulley (y)")
scene.constraint.eq(D.x - C.x, 31.5, description="the small pulley centre is 31.5 to the right of the large one")
scene.constraint.eq(D.y - C.y, 13.6, description="the small pulley centre is 13.6 above the large one")
pulley_C = scene.add.circle(C)
pulley_D = scene.add.circle(D)
scene.constraint.eq(2 * pulley_C.radius, 15.9, description="the large pulley is 15.9 across")
scene.constraint.eq(2 * pulley_D.radius, 7.7, description="the small pulley is 7.7 across")
belt = scene.add.line(T, V)
scene.relate.tangent_to_circle(belt, pulley_C, T)
scene.relate.tangent_to_circle(belt, pulley_D, V)
scene.constraint.gt(cross(C, D, T), 0.05, description="the belt run passes over the TOP of both pulleys")
scene.constraint.gt(dot(C, T, D, V), 0.05, description="the belt does not cross over between the pulleys: it touches both on the same side")

each pulley radius is half the stated across-size

'touching' means the belt line is tangent to both circles

the perpendicular distance from each centre to the belt equals that pulley's radius

both tangency points are the feet of the perpendiculars from the centres

'does not cross over' selects the external common tangent, not the internal one

'over the tops' picks the upper of the two external tangents


A bracket carries two pulleys. Set up coordinates with the centre of the large pulley at the origin C; the centre of the small pulley is at D, 29.5 mm to the right and 10.7 mm above it. The large pulley is 21.3 mm across and the small one is 8.4 mm across. A straight belt run passes over the tops of both pulleys, touching the large one at T and the small one at V. The belt does not cross over between the two pulleys.

"""Belt run tangent to two pulleys

Oracle formalization for cad_t1_cad_belt_tangent_0046. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(43)

C, D, T, V = scene.add.points(["C", "D", "T", "V"])

scene.constraint.eq(C.x, 0, description="datum: C is the origin, the centre of the large pulley (x)")
scene.constraint.eq(C.y, 0, description="datum: C is the origin, the centre of the large pulley (y)")
scene.constraint.eq(D.x - C.x, 29.5, description="the small pulley centre is 29.5 to the right of the large one")
scene.constraint.eq(D.y - C.y, 10.7, description="the small pulley centre is 10.7 above the large one")
pulley_C = scene.add.circle(C)
pulley_D = scene.add.circle(D)
scene.constraint.eq(2 * pulley_C.radius, 21.3, description="the large pulley is 21.3 across")
scene.constraint.eq(2 * pulley_D.radius, 8.4, description="the small pulley is 8.4 across")
belt = scene.add.line(T, V)
scene.relate.tangent_to_circle(belt, pulley_C, T)
scene.relate.tangent_to_circle(belt, pulley_D, V)
scene.constraint.gt(cross(C, D, T), 0.05, description="the belt run passes over the TOP of both pulleys")
scene.constraint.gt(dot(C, T, D, V), 0.05, description="the belt does not cross over between the pulleys: it touches both on the same side")


A bracket carries two pulleys. Set up coordinates with the centre of the large pulley at the origin C; the centre of the small pulley is at D, 21.3 mm to the right and 8.1 mm above it. The large pulley is 21.1 mm across and the small one is 12.9 mm across. A straight belt run passes over the tops of both pulleys, touching the large one at T and the small one at V. The belt does not cross over between the two pulleys.

"""Belt run tangent to two pulleys

Oracle formalization for cad_t1_cad_belt_tangent_0047. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(33)

C, D, T, V = scene.add.points(["C", "D", "T", "V"])

scene.constraint.eq(C.x, 0, description="datum: C is the origin, the centre of the large pulley (x)")
scene.constraint.eq(C.y, 0, description="datum: C is the origin, the centre of the large pulley (y)")
scene.constraint.eq(D.x - C.x, 21.3, description="the small pulley centre is 21.3 to the right of the large one")
scene.constraint.eq(D.y - C.y, 8.1, description="the small pulley centre is 8.1 above the large one")
pulley_C = scene.add.circle(C)
pulley_D = scene.add.circle(D)
scene.constraint.eq(2 * pulley_C.radius, 21.1, description="the large pulley is 21.1 across")
scene.constraint.eq(2 * pulley_D.radius, 12.9, description="the small pulley is 12.9 across")
belt = scene.add.line(T, V)
scene.relate.tangent_to_circle(belt, pulley_C, T)
scene.relate.tangent_to_circle(belt, pulley_D, V)
scene.constraint.gt(cross(C, D, T), 0.05, description="the belt run passes over the TOP of both pulleys")
scene.constraint.gt(dot(C, T, D, V), 0.05, description="the belt does not cross over between the pulleys: it touches both on the same side")


A bracket carries two pulleys. Set up coordinates with the centre of the large pulley at the origin C; the centre of the small pulley is at D, 21.2 mm to the right and 5.8 mm above it. The large pulley is 15.1 mm across and the small one is 7.5 mm across. A straight belt run passes over the tops of both pulleys, touching the large one at T and the small one at V. The belt does not cross over between the two pulleys.

"""Belt run tangent to two pulleys

Oracle formalization for cad_t1_cad_belt_tangent_0048. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(33)

C, D, T, V = scene.add.points(["C", "D", "T", "V"])

scene.constraint.eq(C.x, 0, description="datum: C is the origin, the centre of the large pulley (x)")
scene.constraint.eq(C.y, 0, description="datum: C is the origin, the centre of the large pulley (y)")
scene.constraint.eq(D.x - C.x, 21.2, description="the small pulley centre is 21.2 to the right of the large one")
scene.constraint.eq(D.y - C.y, 5.8, description="the small pulley centre is 5.8 above the large one")
pulley_C = scene.add.circle(C)
pulley_D = scene.add.circle(D)
scene.constraint.eq(2 * pulley_C.radius, 15.1, description="the large pulley is 15.1 across")
scene.constraint.eq(2 * pulley_D.radius, 7.5, description="the small pulley is 7.5 across")
belt = scene.add.line(T, V)
scene.relate.tangent_to_circle(belt, pulley_C, T)
scene.relate.tangent_to_circle(belt, pulley_D, V)
scene.constraint.gt(cross(C, D, T), 0.05, description="the belt run passes over the TOP of both pulleys")
scene.constraint.gt(dot(C, T, D, V), 0.05, description="the belt does not cross over between the pulleys: it touches both on the same side")


A bracket carries two pulleys. Set up coordinates with the centre of the large pulley at the origin C; the centre of the small pulley is at D, 27.4 mm to the right and 7.1 mm above it. The large pulley is 18.3 mm across and the small one is 12.5 mm across. A straight belt run passes over the tops of both pulleys, touching the large one at T and the small one at V. The belt does not cross over between the two pulleys.

"""Belt run tangent to two pulleys

Oracle formalization for cad_t1_cad_belt_tangent_0049. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(41)

C, D, T, V = scene.add.points(["C", "D", "T", "V"])

scene.constraint.eq(C.x, 0, description="datum: C is the origin, the centre of the large pulley (x)")
scene.constraint.eq(C.y, 0, description="datum: C is the origin, the centre of the large pulley (y)")
scene.constraint.eq(D.x - C.x, 27.4, description="the small pulley centre is 27.4 to the right of the large one")
scene.constraint.eq(D.y - C.y, 7.1, description="the small pulley centre is 7.1 above the large one")
pulley_C = scene.add.circle(C)
pulley_D = scene.add.circle(D)
scene.constraint.eq(2 * pulley_C.radius, 18.3, description="the large pulley is 18.3 across")
scene.constraint.eq(2 * pulley_D.radius, 12.5, description="the small pulley is 12.5 across")
belt = scene.add.line(T, V)
scene.relate.tangent_to_circle(belt, pulley_C, T)
scene.relate.tangent_to_circle(belt, pulley_D, V)
scene.constraint.gt(cross(C, D, T), 0.05, description="the belt run passes over the TOP of both pulleys")
scene.constraint.gt(dot(C, T, D, V), 0.05, description="the belt does not cross over between the pulleys: it touches both on the same side")


A bracket carries two pulleys. Set up coordinates with the centre of the large pulley at the origin C; the centre of the small pulley is at D, 22.8 mm to the right and 5.7 mm above it. The large pulley is 19.5 mm across and the small one is 11.6 mm across. A straight belt run passes over the tops of both pulleys, touching the large one at T and the small one at V. The belt does not cross over between the two pulleys.

"""Belt run tangent to two pulleys

Oracle formalization for cad_t1_cad_belt_tangent_0050. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(35)

C, D, T, V = scene.add.points(["C", "D", "T", "V"])

scene.constraint.eq(C.x, 0, description="datum: C is the origin, the centre of the large pulley (x)")
scene.constraint.eq(C.y, 0, description="datum: C is the origin, the centre of the large pulley (y)")
scene.constraint.eq(D.x - C.x, 22.8, description="the small pulley centre is 22.8 to the right of the large one")
scene.constraint.eq(D.y - C.y, 5.7, description="the small pulley centre is 5.7 above the large one")
pulley_C = scene.add.circle(C)
pulley_D = scene.add.circle(D)
scene.constraint.eq(2 * pulley_C.radius, 19.5, description="the large pulley is 19.5 across")
scene.constraint.eq(2 * pulley_D.radius, 11.6, description="the small pulley is 11.6 across")
belt = scene.add.line(T, V)
scene.relate.tangent_to_circle(belt, pulley_C, T)
scene.relate.tangent_to_circle(belt, pulley_D, V)
scene.constraint.gt(cross(C, D, T), 0.05, description="the belt run passes over the TOP of both pulleys")
scene.constraint.gt(dot(C, T, D, V), 0.05, description="the belt does not cross over between the pulleys: it touches both on the same side")


A bracket carries two pulleys. Set up coordinates with the centre of the large pulley at the origin C; the centre of the small pulley is at D, 29.1 mm to the right and 5.6 mm above it. The large pulley is 18.2 mm across and the small one is 11.8 mm across. A straight belt run passes over the tops of both pulleys, touching the large one at T and the small one at V. The belt does not cross over between the two pulleys.

"""Belt run tangent to two pulleys

Oracle formalization for cad_t1_cad_belt_tangent_0051. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(43)

C, D, T, V = scene.add.points(["C", "D", "T", "V"])

scene.constraint.eq(C.x, 0, description="datum: C is the origin, the centre of the large pulley (x)")
scene.constraint.eq(C.y, 0, description="datum: C is the origin, the centre of the large pulley (y)")
scene.constraint.eq(D.x - C.x, 29.1, description="the small pulley centre is 29.1 to the right of the large one")
scene.constraint.eq(D.y - C.y, 5.6, description="the small pulley centre is 5.6 above the large one")
pulley_C = scene.add.circle(C)
pulley_D = scene.add.circle(D)
scene.constraint.eq(2 * pulley_C.radius, 18.2, description="the large pulley is 18.2 across")
scene.constraint.eq(2 * pulley_D.radius, 11.8, description="the small pulley is 11.8 across")
belt = scene.add.line(T, V)
scene.relate.tangent_to_circle(belt, pulley_C, T)
scene.relate.tangent_to_circle(belt, pulley_D, V)
scene.constraint.gt(cross(C, D, T), 0.05, description="the belt run passes over the TOP of both pulleys")
scene.constraint.gt(dot(C, T, D, V), 0.05, description="the belt does not cross over between the pulleys: it touches both on the same side")


A bracket carries two pulleys. Set up coordinates with the centre of the large pulley at the origin C; the centre of the small pulley is at D, 32.4 mm to the right and 9.9 mm above it. The large pulley is 22.5 mm across and the small one is 7.6 mm across. A straight belt run passes over the tops of both pulleys, touching the large one at T and the small one at V. The belt does not cross over between the two pulleys.

"""Belt run tangent to two pulleys

Oracle formalization for cad_t1_cad_belt_tangent_0052. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(47)

C, D, T, V = scene.add.points(["C", "D", "T", "V"])

scene.constraint.eq(C.x, 0, description="datum: C is the origin, the centre of the large pulley (x)")
scene.constraint.eq(C.y, 0, description="datum: C is the origin, the centre of the large pulley (y)")
scene.constraint.eq(D.x - C.x, 32.4, description="the small pulley centre is 32.4 to the right of the large one")
scene.constraint.eq(D.y - C.y, 9.9, description="the small pulley centre is 9.9 above the large one")
pulley_C = scene.add.circle(C)
pulley_D = scene.add.circle(D)
scene.constraint.eq(2 * pulley_C.radius, 22.5, description="the large pulley is 22.5 across")
scene.constraint.eq(2 * pulley_D.radius, 7.6, description="the small pulley is 7.6 across")
belt = scene.add.line(T, V)
scene.relate.tangent_to_circle(belt, pulley_C, T)
scene.relate.tangent_to_circle(belt, pulley_D, V)
scene.constraint.gt(cross(C, D, T), 0.05, description="the belt run passes over the TOP of both pulleys")
scene.constraint.gt(dot(C, T, D, V), 0.05, description="the belt does not cross over between the pulleys: it touches both on the same side")


A triangular gusset plate has two straight edges meeting at a square corner. Set up coordinates with that square corner at the origin G, one edge running from G along the positive x-direction to A, and the other running from G along the positive y-direction to B. Edge GA is 33.8 mm long and edge GB is 22.8 mm long; the third edge of the plate is the straight line from A to B. A hole 6.1 mm across is drilled with its centre at N, 12.8 mm from the square corner and positioned so that it sits the same distance from edge GA as it does from edge GB. The design requires at least 2.5 mm of material to remain between the hole and every edge of the plate.

"""Gusset plate with a clearance hole

Oracle formalization for cad_t1_cad_gusset_hole_0069. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(49)

G, A, B, N = scene.add.points(["G", "A", "B", "N"])

scene.constraint.eq(G.x, 0, description="datum: G is the origin, the square corner of the gusset (x)")
scene.constraint.eq(G.y, 0, description="datum: G is the origin, the square corner of the gusset (y)")
scene.constraint.eq(A.y, 0, description="datum: edge GA runs along the x-axis")
scene.constraint.gt(A.x, 1.0, description="datum: edge GA runs in the +x direction")
scene.constraint.eq(G.distance(A), 33.8, description="edge GA is 33.8 long")
scene.constraint.eq(G.distance(B), 22.8, description="edge GB is 22.8 long")
scene.relate.right_angle(A, G, B)
scene.constraint.gt(B.y, 1.0, description="datum: edge GB runs in the +y direction")
scene.constraint.eq(N.x, N.y, description="the hole centre is the same distance from edge GA as from edge GB")
scene.constraint.eq(G.distance(N), 12.8, description="the hole centre is 12.8 from the square corner")
scene.constraint.geq(N.y, 5.55, description="at least 2.5 of material between the hole and edge GA")
scene.constraint.geq(N.x, 5.55, description="at least 2.5 of material between the hole and edge GB")
scene.constraint.geq(cross(A, B, N) / A.distance(B), 5.55, description="at least 2.5 of material between the hole and the sloping edge AB")

the hole radius is half the stated across-size

'the same distance from both edges' puts the centre on the 45 degree bisector of the square corner

the clearance is measured from the hole EDGE, so the centre must be at least clearance + hole radius from each edge

the clearance to the sloping edge needs the perpendicular distance from N to the line AB

edge GB runs in the +y direction, which fixes which side the plate is on


A triangular gusset plate has two straight edges meeting at a square corner. Set up coordinates with that square corner at the origin G, one edge running from G along the positive x-direction to A, and the other running from G along the positive y-direction to B. Edge GA is 31.5 mm long and edge GB is 19.1 mm long; the third edge of the plate is the straight line from A to B. A hole 6.4 mm across is drilled with its centre at N, 10.5 mm from the square corner and positioned so that it sits the same distance from edge GA as it does from edge GB. The design requires at least 1.9 mm of material to remain between the hole and every edge of the plate.

"""Gusset plate with a clearance hole

Oracle formalization for cad_t1_cad_gusset_hole_0070. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(46)

G, A, B, N = scene.add.points(["G", "A", "B", "N"])

scene.constraint.eq(G.x, 0, description="datum: G is the origin, the square corner of the gusset (x)")
scene.constraint.eq(G.y, 0, description="datum: G is the origin, the square corner of the gusset (y)")
scene.constraint.eq(A.y, 0, description="datum: edge GA runs along the x-axis")
scene.constraint.gt(A.x, 1.0, description="datum: edge GA runs in the +x direction")
scene.constraint.eq(G.distance(A), 31.5, description="edge GA is 31.5 long")
scene.constraint.eq(G.distance(B), 19.1, description="edge GB is 19.1 long")
scene.relate.right_angle(A, G, B)
scene.constraint.gt(B.y, 1.0, description="datum: edge GB runs in the +y direction")
scene.constraint.eq(N.x, N.y, description="the hole centre is the same distance from edge GA as from edge GB")
scene.constraint.eq(G.distance(N), 10.5, description="the hole centre is 10.5 from the square corner")
scene.constraint.geq(N.y, 5.1, description="at least 1.9 of material between the hole and edge GA")
scene.constraint.geq(N.x, 5.1, description="at least 1.9 of material between the hole and edge GB")
scene.constraint.geq(cross(A, B, N) / A.distance(B), 5.1, description="at least 1.9 of material between the hole and the sloping edge AB")


A triangular gusset plate has two straight edges meeting at a square corner. Set up coordinates with that square corner at the origin G, one edge running from G along the positive x-direction to A, and the other running from G along the positive y-direction to B. Edge GA is 28.5 mm long and edge GB is 25 mm long; the third edge of the plate is the straight line from A to B. A hole 6.7 mm across is drilled with its centre at N, 12.3 mm from the square corner and positioned so that it sits the same distance from edge GA as it does from edge GB. The design requires at least 2.1 mm of material to remain between the hole and every edge of the plate.

"""Gusset plate with a clearance hole

Oracle formalization for cad_t1_cad_gusset_hole_0071. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(42)

G, A, B, N = scene.add.points(["G", "A", "B", "N"])

scene.constraint.eq(G.x, 0, description="datum: G is the origin, the square corner of the gusset (x)")
scene.constraint.eq(G.y, 0, description="datum: G is the origin, the square corner of the gusset (y)")
scene.constraint.eq(A.y, 0, description="datum: edge GA runs along the x-axis")
scene.constraint.gt(A.x, 1.0, description="datum: edge GA runs in the +x direction")
scene.constraint.eq(G.distance(A), 28.5, description="edge GA is 28.5 long")
scene.constraint.eq(G.distance(B), 25, description="edge GB is 25 long")
scene.relate.right_angle(A, G, B)
scene.constraint.gt(B.y, 1.0, description="datum: edge GB runs in the +y direction")
scene.constraint.eq(N.x, N.y, description="the hole centre is the same distance from edge GA as from edge GB")
scene.constraint.eq(G.distance(N), 12.3, description="the hole centre is 12.3 from the square corner")
scene.constraint.geq(N.y, 5.45, description="at least 2.1 of material between the hole and edge GA")
scene.constraint.geq(N.x, 5.45, description="at least 2.1 of material between the hole and edge GB")
scene.constraint.geq(cross(A, B, N) / A.distance(B), 5.45, description="at least 2.1 of material between the hole and the sloping edge AB")


A triangular gusset plate has two straight edges meeting at a square corner. Set up coordinates with that square corner at the origin G, one edge running from G along the positive x-direction to A, and the other running from G along the positive y-direction to B. Edge GA is 28.9 mm long and edge GB is 25.5 mm long; the third edge of the plate is the straight line from A to B. A hole 5.6 mm across is drilled with its centre at N, 12.8 mm from the square corner and positioned so that it sits the same distance from edge GA as it does from edge GB. The design requires at least 2.5 mm of material to remain between the hole and every edge of the plate.

"""Gusset plate with a clearance hole

Oracle formalization for cad_t1_cad_gusset_hole_0072. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(43)

G, A, B, N = scene.add.points(["G", "A", "B", "N"])

scene.constraint.eq(G.x, 0, description="datum: G is the origin, the square corner of the gusset (x)")
scene.constraint.eq(G.y, 0, description="datum: G is the origin, the square corner of the gusset (y)")
scene.constraint.eq(A.y, 0, description="datum: edge GA runs along the x-axis")
scene.constraint.gt(A.x, 1.0, description="datum: edge GA runs in the +x direction")
scene.constraint.eq(G.distance(A), 28.9, description="edge GA is 28.9 long")
scene.constraint.eq(G.distance(B), 25.5, description="edge GB is 25.5 long")
scene.relate.right_angle(A, G, B)
scene.constraint.gt(B.y, 1.0, description="datum: edge GB runs in the +y direction")
scene.constraint.eq(N.x, N.y, description="the hole centre is the same distance from edge GA as from edge GB")
scene.constraint.eq(G.distance(N), 12.8, description="the hole centre is 12.8 from the square corner")
scene.constraint.geq(N.y, 5.3, description="at least 2.5 of material between the hole and edge GA")
scene.constraint.geq(N.x, 5.3, description="at least 2.5 of material between the hole and edge GB")
scene.constraint.geq(cross(A, B, N) / A.distance(B), 5.3, description="at least 2.5 of material between the hole and the sloping edge AB")


A triangular gusset plate has two straight edges meeting at a square corner. Set up coordinates with that square corner at the origin G, one edge running from G along the positive x-direction to A, and the other running from G along the positive y-direction to B. Edge GA is 30.9 mm long and edge GB is 20.6 mm long; the third edge of the plate is the straight line from A to B. A hole 6.9 mm across is drilled with its centre at N, 9.5 mm from the square corner and positioned so that it sits the same distance from edge GA as it does from edge GB. The design requires at least 2.6 mm of material to remain between the hole and every edge of the plate.

"""Gusset plate with a clearance hole

Oracle formalization for cad_t1_cad_gusset_hole_0073. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(45)

G, A, B, N = scene.add.points(["G", "A", "B", "N"])

scene.constraint.eq(G.x, 0, description="datum: G is the origin, the square corner of the gusset (x)")
scene.constraint.eq(G.y, 0, description="datum: G is the origin, the square corner of the gusset (y)")
scene.constraint.eq(A.y, 0, description="datum: edge GA runs along the x-axis")
scene.constraint.gt(A.x, 1.0, description="datum: edge GA runs in the +x direction")
scene.constraint.eq(G.distance(A), 30.9, description="edge GA is 30.9 long")
scene.constraint.eq(G.distance(B), 20.6, description="edge GB is 20.6 long")
scene.relate.right_angle(A, G, B)
scene.constraint.gt(B.y, 1.0, description="datum: edge GB runs in the +y direction")
scene.constraint.eq(N.x, N.y, description="the hole centre is the same distance from edge GA as from edge GB")
scene.constraint.eq(G.distance(N), 9.5, description="the hole centre is 9.5 from the square corner")
scene.constraint.geq(N.y, 6.05, description="at least 2.6 of material between the hole and edge GA")
scene.constraint.geq(N.x, 6.05, description="at least 2.6 of material between the hole and edge GB")
scene.constraint.geq(cross(A, B, N) / A.distance(B), 6.05, description="at least 2.6 of material between the hole and the sloping edge AB")


A triangular gusset plate has two straight edges meeting at a square corner. Set up coordinates with that square corner at the origin G, one edge running from G along the positive x-direction to A, and the other running from G along the positive y-direction to B. Edge GA is 33.5 mm long and edge GB is 21.9 mm long; the third edge of the plate is the straight line from A to B. A hole 5.1 mm across is drilled with its centre at N, 10.6 mm from the square corner and positioned so that it sits the same distance from edge GA as it does from edge GB. The design requires at least 2.6 mm of material to remain between the hole and every edge of the plate.

"""Gusset plate with a clearance hole

Oracle formalization for cad_t1_cad_gusset_hole_0074. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(49)

G, A, B, N = scene.add.points(["G", "A", "B", "N"])

scene.constraint.eq(G.x, 0, description="datum: G is the origin, the square corner of the gusset (x)")
scene.constraint.eq(G.y, 0, description="datum: G is the origin, the square corner of the gusset (y)")
scene.constraint.eq(A.y, 0, description="datum: edge GA runs along the x-axis")
scene.constraint.gt(A.x, 1.0, description="datum: edge GA runs in the +x direction")
scene.constraint.eq(G.distance(A), 33.5, description="edge GA is 33.5 long")
scene.constraint.eq(G.distance(B), 21.9, description="edge GB is 21.9 long")
scene.relate.right_angle(A, G, B)
scene.constraint.gt(B.y, 1.0, description="datum: edge GB runs in the +y direction")
scene.constraint.eq(N.x, N.y, description="the hole centre is the same distance from edge GA as from edge GB")
scene.constraint.eq(G.distance(N), 10.6, description="the hole centre is 10.6 from the square corner")
scene.constraint.geq(N.y, 5.15, description="at least 2.6 of material between the hole and edge GA")
scene.constraint.geq(N.x, 5.15, description="at least 2.6 of material between the hole and edge GB")
scene.constraint.geq(cross(A, B, N) / A.distance(B), 5.15, description="at least 2.6 of material between the hole and the sloping edge AB")


A triangular gusset plate has two straight edges meeting at a square corner. Set up coordinates with that square corner at the origin G, one edge running from G along the positive x-direction to A, and the other running from G along the positive y-direction to B. Edge GA is 32.8 mm long and edge GB is 18.3 mm long; the third edge of the plate is the straight line from A to B. A hole 5.1 mm across is drilled with its centre at N, 8.7 mm from the square corner and positioned so that it sits the same distance from edge GA as it does from edge GB. The design requires at least 2.7 mm of material to remain between the hole and every edge of the plate.

"""Gusset plate with a clearance hole

Oracle formalization for cad_t1_cad_gusset_hole_0075. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(48)

G, A, B, N = scene.add.points(["G", "A", "B", "N"])

scene.constraint.eq(G.x, 0, description="datum: G is the origin, the square corner of the gusset (x)")
scene.constraint.eq(G.y, 0, description="datum: G is the origin, the square corner of the gusset (y)")
scene.constraint.eq(A.y, 0, description="datum: edge GA runs along the x-axis")
scene.constraint.gt(A.x, 1.0, description="datum: edge GA runs in the +x direction")
scene.constraint.eq(G.distance(A), 32.8, description="edge GA is 32.8 long")
scene.constraint.eq(G.distance(B), 18.3, description="edge GB is 18.3 long")
scene.relate.right_angle(A, G, B)
scene.constraint.gt(B.y, 1.0, description="datum: edge GB runs in the +y direction")
scene.constraint.eq(N.x, N.y, description="the hole centre is the same distance from edge GA as from edge GB")
scene.constraint.eq(G.distance(N), 8.7, description="the hole centre is 8.7 from the square corner")
scene.constraint.geq(N.y, 5.25, description="at least 2.7 of material between the hole and edge GA")
scene.constraint.geq(N.x, 5.25, description="at least 2.7 of material between the hole and edge GB")
scene.constraint.geq(cross(A, B, N) / A.distance(B), 5.25, description="at least 2.7 of material between the hole and the sloping edge AB")


A triangular gusset plate has two straight edges meeting at a square corner. Set up coordinates with that square corner at the origin G, one edge running from G along the positive x-direction to A, and the other running from G along the positive y-direction to B. Edge GA is 31 mm long and edge GB is 22.6 mm long; the third edge of the plate is the straight line from A to B. A hole 6.3 mm across is drilled with its centre at N, 11.3 mm from the square corner and positioned so that it sits the same distance from edge GA as it does from edge GB. The design requires at least 1.6 mm of material to remain between the hole and every edge of the plate.

"""Gusset plate with a clearance hole

Oracle formalization for cad_t1_cad_gusset_hole_0076. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(45)

G, A, B, N = scene.add.points(["G", "A", "B", "N"])

scene.constraint.eq(G.x, 0, description="datum: G is the origin, the square corner of the gusset (x)")
scene.constraint.eq(G.y, 0, description="datum: G is the origin, the square corner of the gusset (y)")
scene.constraint.eq(A.y, 0, description="datum: edge GA runs along the x-axis")
scene.constraint.gt(A.x, 1.0, description="datum: edge GA runs in the +x direction")
scene.constraint.eq(G.distance(A), 31, description="edge GA is 31 long")
scene.constraint.eq(G.distance(B), 22.6, description="edge GB is 22.6 long")
scene.relate.right_angle(A, G, B)
scene.constraint.gt(B.y, 1.0, description="datum: edge GB runs in the +y direction")
scene.constraint.eq(N.x, N.y, description="the hole centre is the same distance from edge GA as from edge GB")
scene.constraint.eq(G.distance(N), 11.3, description="the hole centre is 11.3 from the square corner")
scene.constraint.geq(N.y, 4.75, description="at least 1.6 of material between the hole and edge GA")
scene.constraint.geq(N.x, 4.75, description="at least 1.6 of material between the hole and edge GB")
scene.constraint.geq(cross(A, B, N) / A.distance(B), 4.75, description="at least 1.6 of material between the hole and the sloping edge AB")


A rectangular bracket measures 38.4 mm by 24.5 mm. Set up coordinates with the bottom-left corner at the origin P, the 38.4 mm edge running from P along the positive x-direction to Q, and the 24.5 mm edge running from P along the positive y-direction to S; R is the remaining corner. Three holes, each 6.3 mm across, are drilled through it. The centre of the first, N1, is 6.8 mm from edge PS and 5.1 mm from edge PQ. The centre of the second, N2, is 25.3 mm from edge PS and 18.8 mm from edge PQ. The third hole centre N3 is 11 mm from edge PQ, and it must sit the same distance from the first hole as from the second. At least 1.7 mm of material must remain between the third hole and every edge of the bracket.

"""Three-hole bracket, third hole equidistant

Oracle formalization for cad_t1_cad_three_hole_0085. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(55)

P, Q, R, S, N1, N2, N3 = scene.add.points(["P", "Q", "R", "S", "N1", "N2", "N3"])

scene.constraint.eq(P.x, 0, description="datum: P is the origin, the datum corner of the bracket (x)")
scene.constraint.eq(P.y, 0, description="datum: P is the origin, the datum corner of the bracket (y)")
scene.constraint.eq(Q.y, 0, description="datum: edge PQ runs along the x-axis")
scene.constraint.gt(Q.x, 1.0, description="datum: the bracket lies in the +x direction from P")
scene.constraint.eq(P.distance(Q), 38.4, description="bracket is 38.4 long along PQ")
scene.constraint.eq(P.distance(S), 24.5, description="bracket is 24.5 wide along PS")
scene.relate.perpendicular(scene.add.line_segment(P, Q), scene.add.line_segment(P, S))
scene.constraint.gt(S.y, 1.0, description="datum: the bracket lies in the +y direction from P")
scene.constraint.eq(R.x, Q.x + S.x - P.x, description="bracket corner R closes the rectangle (x)")
scene.constraint.eq(R.y, Q.y + S.y - P.y, description="bracket corner R closes the rectangle (y)")
scene.constraint.eq(N1.x, 6.8, description="hole 1 is 6.8 from the datum edge PS")
scene.constraint.eq(N1.y, 5.1, description="hole 1 is 5.1 from the datum edge PQ")
scene.constraint.eq(N2.x, 25.3, description="hole 2 is 25.3 from the datum edge PS")
scene.constraint.eq(N2.y, 18.8, description="hole 2 is 18.8 from the datum edge PQ")
scene.constraint.eq(N3.y, 11, description="hole 3 is 11 from the datum edge PQ")
scene.constraint.eq(N3.distance(N1), N3.distance(N2), description="hole 3 is the same distance from hole 1 as from hole 2")
scene.constraint.geq(N3.y, 4.85, description="at least 1.7 of material between hole 3 and edge PQ")
scene.constraint.geq(N3.x, 4.85, description="at least 1.7 of material between hole 3 and edge PS")
scene.constraint.geq(Q.x - N3.x, 4.85, description="at least 1.7 of material between hole 3 and edge QR")
scene.constraint.geq(S.y - N3.y, 4.85, description="at least 1.7 of material between hole 3 and edge SR")

each hole radius is half the stated across-size

'the same distance from the first hole as from the second' puts N3 on the perpendicular bisector of N1N2

combined with the stated height, that pins N3 completely

edge clearance is measured from the hole edge, so it uses clearance + hole radius from the centre


A rectangular bracket measures 45.8 mm by 25.9 mm. Set up coordinates with the bottom-left corner at the origin P, the 45.8 mm edge running from P along the positive x-direction to Q, and the 25.9 mm edge running from P along the positive y-direction to S; R is the remaining corner. Three holes, each 4.9 mm across, are drilled through it. The centre of the first, N1, is 8.8 mm from edge PS and 8.6 mm from edge PQ. The centre of the second, N2, is 24.7 mm from edge PS and 17.5 mm from edge PQ. The third hole centre N3 is 13.7 mm from edge PQ, and it must sit the same distance from the first hole as from the second. At least 1.8 mm of material must remain between the third hole and every edge of the bracket.

"""Three-hole bracket, third hole equidistant

Oracle formalization for cad_t1_cad_three_hole_0086. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(65)

P, Q, R, S, N1, N2, N3 = scene.add.points(["P", "Q", "R", "S", "N1", "N2", "N3"])

scene.constraint.eq(P.x, 0, description="datum: P is the origin, the datum corner of the bracket (x)")
scene.constraint.eq(P.y, 0, description="datum: P is the origin, the datum corner of the bracket (y)")
scene.constraint.eq(Q.y, 0, description="datum: edge PQ runs along the x-axis")
scene.constraint.gt(Q.x, 1.0, description="datum: the bracket lies in the +x direction from P")
scene.constraint.eq(P.distance(Q), 45.8, description="bracket is 45.8 long along PQ")
scene.constraint.eq(P.distance(S), 25.9, description="bracket is 25.9 wide along PS")
scene.relate.perpendicular(scene.add.line_segment(P, Q), scene.add.line_segment(P, S))
scene.constraint.gt(S.y, 1.0, description="datum: the bracket lies in the +y direction from P")
scene.constraint.eq(R.x, Q.x + S.x - P.x, description="bracket corner R closes the rectangle (x)")
scene.constraint.eq(R.y, Q.y + S.y - P.y, description="bracket corner R closes the rectangle (y)")
scene.constraint.eq(N1.x, 8.8, description="hole 1 is 8.8 from the datum edge PS")
scene.constraint.eq(N1.y, 8.6, description="hole 1 is 8.6 from the datum edge PQ")
scene.constraint.eq(N2.x, 24.7, description="hole 2 is 24.7 from the datum edge PS")
scene.constraint.eq(N2.y, 17.5, description="hole 2 is 17.5 from the datum edge PQ")
scene.constraint.eq(N3.y, 13.7, description="hole 3 is 13.7 from the datum edge PQ")
scene.constraint.eq(N3.distance(N1), N3.distance(N2), description="hole 3 is the same distance from hole 1 as from hole 2")
scene.constraint.geq(N3.y, 4.25, description="at least 1.8 of material between hole 3 and edge PQ")
scene.constraint.geq(N3.x, 4.25, description="at least 1.8 of material between hole 3 and edge PS")
scene.constraint.geq(Q.x - N3.x, 4.25, description="at least 1.8 of material between hole 3 and edge QR")
scene.constraint.geq(S.y - N3.y, 4.25, description="at least 1.8 of material between hole 3 and edge SR")


A rectangular bracket measures 43.5 mm by 29.2 mm. Set up coordinates with the bottom-left corner at the origin P, the 43.5 mm edge running from P along the positive x-direction to Q, and the 29.2 mm edge running from P along the positive y-direction to S; R is the remaining corner. Three holes, each 6 mm across, are drilled through it. The centre of the first, N1, is 6.5 mm from edge PS and 6.5 mm from edge PQ. The centre of the second, N2, is 28.3 mm from edge PS and 16.8 mm from edge PQ. The third hole centre N3 is 12.4 mm from edge PQ, and it must sit the same distance from the first hole as from the second. At least 1.9 mm of material must remain between the third hole and every edge of the bracket.

"""Three-hole bracket, third hole equidistant

Oracle formalization for cad_t1_cad_three_hole_0087. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(62)

P, Q, R, S, N1, N2, N3 = scene.add.points(["P", "Q", "R", "S", "N1", "N2", "N3"])

scene.constraint.eq(P.x, 0, description="datum: P is the origin, the datum corner of the bracket (x)")
scene.constraint.eq(P.y, 0, description="datum: P is the origin, the datum corner of the bracket (y)")
scene.constraint.eq(Q.y, 0, description="datum: edge PQ runs along the x-axis")
scene.constraint.gt(Q.x, 1.0, description="datum: the bracket lies in the +x direction from P")
scene.constraint.eq(P.distance(Q), 43.5, description="bracket is 43.5 long along PQ")
scene.constraint.eq(P.distance(S), 29.2, description="bracket is 29.2 wide along PS")
scene.relate.perpendicular(scene.add.line_segment(P, Q), scene.add.line_segment(P, S))
scene.constraint.gt(S.y, 1.0, description="datum: the bracket lies in the +y direction from P")
scene.constraint.eq(R.x, Q.x + S.x - P.x, description="bracket corner R closes the rectangle (x)")
scene.constraint.eq(R.y, Q.y + S.y - P.y, description="bracket corner R closes the rectangle (y)")
scene.constraint.eq(N1.x, 6.5, description="hole 1 is 6.5 from the datum edge PS")
scene.constraint.eq(N1.y, 6.5, description="hole 1 is 6.5 from the datum edge PQ")
scene.constraint.eq(N2.x, 28.3, description="hole 2 is 28.3 from the datum edge PS")
scene.constraint.eq(N2.y, 16.8, description="hole 2 is 16.8 from the datum edge PQ")
scene.constraint.eq(N3.y, 12.4, description="hole 3 is 12.4 from the datum edge PQ")
scene.constraint.eq(N3.distance(N1), N3.distance(N2), description="hole 3 is the same distance from hole 1 as from hole 2")
scene.constraint.geq(N3.y, 4.9, description="at least 1.9 of material between hole 3 and edge PQ")
scene.constraint.geq(N3.x, 4.9, description="at least 1.9 of material between hole 3 and edge PS")
scene.constraint.geq(Q.x - N3.x, 4.9, description="at least 1.9 of material between hole 3 and edge QR")
scene.constraint.geq(S.y - N3.y, 4.9, description="at least 1.9 of material between hole 3 and edge SR")


A rectangular bracket measures 41.4 mm by 30.4 mm. Set up coordinates with the bottom-left corner at the origin P, the 41.4 mm edge running from P along the positive x-direction to Q, and the 30.4 mm edge running from P along the positive y-direction to S; R is the remaining corner. Three holes, each 4.5 mm across, are drilled through it. The centre of the first, N1, is 10.6 mm from edge PS and 5 mm from edge PQ. The centre of the second, N2, is 28.1 mm from edge PS and 16.2 mm from edge PQ. The third hole centre N3 is 16 mm from edge PQ, and it must sit the same distance from the first hole as from the second. At least 2.3 mm of material must remain between the third hole and every edge of the bracket.

"""Three-hole bracket, third hole equidistant

Oracle formalization for cad_t1_cad_three_hole_0088. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(59)

P, Q, R, S, N1, N2, N3 = scene.add.points(["P", "Q", "R", "S", "N1", "N2", "N3"])

scene.constraint.eq(P.x, 0, description="datum: P is the origin, the datum corner of the bracket (x)")
scene.constraint.eq(P.y, 0, description="datum: P is the origin, the datum corner of the bracket (y)")
scene.constraint.eq(Q.y, 0, description="datum: edge PQ runs along the x-axis")
scene.constraint.gt(Q.x, 1.0, description="datum: the bracket lies in the +x direction from P")
scene.constraint.eq(P.distance(Q), 41.4, description="bracket is 41.4 long along PQ")
scene.constraint.eq(P.distance(S), 30.4, description="bracket is 30.4 wide along PS")
scene.relate.perpendicular(scene.add.line_segment(P, Q), scene.add.line_segment(P, S))
scene.constraint.gt(S.y, 1.0, description="datum: the bracket lies in the +y direction from P")
scene.constraint.eq(R.x, Q.x + S.x - P.x, description="bracket corner R closes the rectangle (x)")
scene.constraint.eq(R.y, Q.y + S.y - P.y, description="bracket corner R closes the rectangle (y)")
scene.constraint.eq(N1.x, 10.6, description="hole 1 is 10.6 from the datum edge PS")
scene.constraint.eq(N1.y, 5, description="hole 1 is 5 from the datum edge PQ")
scene.constraint.eq(N2.x, 28.1, description="hole 2 is 28.1 from the datum edge PS")
scene.constraint.eq(N2.y, 16.2, description="hole 2 is 16.2 from the datum edge PQ")
scene.constraint.eq(N3.y, 16, description="hole 3 is 16 from the datum edge PQ")
scene.constraint.eq(N3.distance(N1), N3.distance(N2), description="hole 3 is the same distance from hole 1 as from hole 2")
scene.constraint.geq(N3.y, 4.55, description="at least 2.3 of material between hole 3 and edge PQ")
scene.constraint.geq(N3.x, 4.55, description="at least 2.3 of material between hole 3 and edge PS")
scene.constraint.geq(Q.x - N3.x, 4.55, description="at least 2.3 of material between hole 3 and edge QR")
scene.constraint.geq(S.y - N3.y, 4.55, description="at least 2.3 of material between hole 3 and edge SR")


A rectangular bracket measures 43.3 mm by 26.9 mm. Set up coordinates with the bottom-left corner at the origin P, the 43.3 mm edge running from P along the positive x-direction to Q, and the 26.9 mm edge running from P along the positive y-direction to S; R is the remaining corner. Three holes, each 4.8 mm across, are drilled through it. The centre of the first, N1, is 10.2 mm from edge PS and 5.1 mm from edge PQ. The centre of the second, N2, is 32.4 mm from edge PS and 16.1 mm from edge PQ. The third hole centre N3 is 9.4 mm from edge PQ, and it must sit the same distance from the first hole as from the second. At least 1.8 mm of material must remain between the third hole and every edge of the bracket.

"""Three-hole bracket, third hole equidistant

Oracle formalization for cad_t1_cad_three_hole_0089. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(61)

P, Q, R, S, N1, N2, N3 = scene.add.points(["P", "Q", "R", "S", "N1", "N2", "N3"])

scene.constraint.eq(P.x, 0, description="datum: P is the origin, the datum corner of the bracket (x)")
scene.constraint.eq(P.y, 0, description="datum: P is the origin, the datum corner of the bracket (y)")
scene.constraint.eq(Q.y, 0, description="datum: edge PQ runs along the x-axis")
scene.constraint.gt(Q.x, 1.0, description="datum: the bracket lies in the +x direction from P")
scene.constraint.eq(P.distance(Q), 43.3, description="bracket is 43.3 long along PQ")
scene.constraint.eq(P.distance(S), 26.9, description="bracket is 26.9 wide along PS")
scene.relate.perpendicular(scene.add.line_segment(P, Q), scene.add.line_segment(P, S))
scene.constraint.gt(S.y, 1.0, description="datum: the bracket lies in the +y direction from P")
scene.constraint.eq(R.x, Q.x + S.x - P.x, description="bracket corner R closes the rectangle (x)")
scene.constraint.eq(R.y, Q.y + S.y - P.y, description="bracket corner R closes the rectangle (y)")
scene.constraint.eq(N1.x, 10.2, description="hole 1 is 10.2 from the datum edge PS")
scene.constraint.eq(N1.y, 5.1, description="hole 1 is 5.1 from the datum edge PQ")
scene.constraint.eq(N2.x, 32.4, description="hole 2 is 32.4 from the datum edge PS")
scene.constraint.eq(N2.y, 16.1, description="hole 2 is 16.1 from the datum edge PQ")
scene.constraint.eq(N3.y, 9.4, description="hole 3 is 9.4 from the datum edge PQ")
scene.constraint.eq(N3.distance(N1), N3.distance(N2), description="hole 3 is the same distance from hole 1 as from hole 2")
scene.constraint.geq(N3.y, 4.2, description="at least 1.8 of material between hole 3 and edge PQ")
scene.constraint.geq(N3.x, 4.2, description="at least 1.8 of material between hole 3 and edge PS")
scene.constraint.geq(Q.x - N3.x, 4.2, description="at least 1.8 of material between hole 3 and edge QR")
scene.constraint.geq(S.y - N3.y, 4.2, description="at least 1.8 of material between hole 3 and edge SR")


A rectangular bracket measures 43.8 mm by 26.3 mm. Set up coordinates with the bottom-left corner at the origin P, the 43.8 mm edge running from P along the positive x-direction to Q, and the 26.3 mm edge running from P along the positive y-direction to S; R is the remaining corner. Three holes, each 6.4 mm across, are drilled through it. The centre of the first, N1, is 7.9 mm from edge PS and 5.9 mm from edge PQ. The centre of the second, N2, is 31.3 mm from edge PS and 16.9 mm from edge PQ. The third hole centre N3 is 12.8 mm from edge PQ, and it must sit the same distance from the first hole as from the second. At least 2.1 mm of material must remain between the third hole and every edge of the bracket.

"""Three-hole bracket, third hole equidistant

Oracle formalization for cad_t1_cad_three_hole_0090. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(62)

P, Q, R, S, N1, N2, N3 = scene.add.points(["P", "Q", "R", "S", "N1", "N2", "N3"])

scene.constraint.eq(P.x, 0, description="datum: P is the origin, the datum corner of the bracket (x)")
scene.constraint.eq(P.y, 0, description="datum: P is the origin, the datum corner of the bracket (y)")
scene.constraint.eq(Q.y, 0, description="datum: edge PQ runs along the x-axis")
scene.constraint.gt(Q.x, 1.0, description="datum: the bracket lies in the +x direction from P")
scene.constraint.eq(P.distance(Q), 43.8, description="bracket is 43.8 long along PQ")
scene.constraint.eq(P.distance(S), 26.3, description="bracket is 26.3 wide along PS")
scene.relate.perpendicular(scene.add.line_segment(P, Q), scene.add.line_segment(P, S))
scene.constraint.gt(S.y, 1.0, description="datum: the bracket lies in the +y direction from P")
scene.constraint.eq(R.x, Q.x + S.x - P.x, description="bracket corner R closes the rectangle (x)")
scene.constraint.eq(R.y, Q.y + S.y - P.y, description="bracket corner R closes the rectangle (y)")
scene.constraint.eq(N1.x, 7.9, description="hole 1 is 7.9 from the datum edge PS")
scene.constraint.eq(N1.y, 5.9, description="hole 1 is 5.9 from the datum edge PQ")
scene.constraint.eq(N2.x, 31.3, description="hole 2 is 31.3 from the datum edge PS")
scene.constraint.eq(N2.y, 16.9, description="hole 2 is 16.9 from the datum edge PQ")
scene.constraint.eq(N3.y, 12.8, description="hole 3 is 12.8 from the datum edge PQ")
scene.constraint.eq(N3.distance(N1), N3.distance(N2), description="hole 3 is the same distance from hole 1 as from hole 2")
scene.constraint.geq(N3.y, 5.3, description="at least 2.1 of material between hole 3 and edge PQ")
scene.constraint.geq(N3.x, 5.3, description="at least 2.1 of material between hole 3 and edge PS")
scene.constraint.geq(Q.x - N3.x, 5.3, description="at least 2.1 of material between hole 3 and edge QR")
scene.constraint.geq(S.y - N3.y, 5.3, description="at least 2.1 of material between hole 3 and edge SR")


A rectangular bracket measures 38.6 mm by 22.9 mm. Set up coordinates with the bottom-left corner at the origin P, the 38.6 mm edge running from P along the positive x-direction to Q, and the 22.9 mm edge running from P along the positive y-direction to S; R is the remaining corner. Three holes, each 6.5 mm across, are drilled through it. The centre of the first, N1, is 11.1 mm from edge PS and 8.5 mm from edge PQ. The centre of the second, N2, is 30.5 mm from edge PS and 14.6 mm from edge PQ. The third hole centre N3 is 9.6 mm from edge PQ, and it must sit the same distance from the first hole as from the second. At least 3 mm of material must remain between the third hole and every edge of the bracket.

"""Three-hole bracket, third hole equidistant

Oracle formalization for cad_t1_cad_three_hole_0091. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(55)

P, Q, R, S, N1, N2, N3 = scene.add.points(["P", "Q", "R", "S", "N1", "N2", "N3"])

scene.constraint.eq(P.x, 0, description="datum: P is the origin, the datum corner of the bracket (x)")
scene.constraint.eq(P.y, 0, description="datum: P is the origin, the datum corner of the bracket (y)")
scene.constraint.eq(Q.y, 0, description="datum: edge PQ runs along the x-axis")
scene.constraint.gt(Q.x, 1.0, description="datum: the bracket lies in the +x direction from P")
scene.constraint.eq(P.distance(Q), 38.6, description="bracket is 38.6 long along PQ")
scene.constraint.eq(P.distance(S), 22.9, description="bracket is 22.9 wide along PS")
scene.relate.perpendicular(scene.add.line_segment(P, Q), scene.add.line_segment(P, S))
scene.constraint.gt(S.y, 1.0, description="datum: the bracket lies in the +y direction from P")
scene.constraint.eq(R.x, Q.x + S.x - P.x, description="bracket corner R closes the rectangle (x)")
scene.constraint.eq(R.y, Q.y + S.y - P.y, description="bracket corner R closes the rectangle (y)")
scene.constraint.eq(N1.x, 11.1, description="hole 1 is 11.1 from the datum edge PS")
scene.constraint.eq(N1.y, 8.5, description="hole 1 is 8.5 from the datum edge PQ")
scene.constraint.eq(N2.x, 30.5, description="hole 2 is 30.5 from the datum edge PS")
scene.constraint.eq(N2.y, 14.6, description="hole 2 is 14.6 from the datum edge PQ")
scene.constraint.eq(N3.y, 9.6, description="hole 3 is 9.6 from the datum edge PQ")
scene.constraint.eq(N3.distance(N1), N3.distance(N2), description="hole 3 is the same distance from hole 1 as from hole 2")
scene.constraint.geq(N3.y, 6.25, description="at least 3 of material between hole 3 and edge PQ")
scene.constraint.geq(N3.x, 6.25, description="at least 3 of material between hole 3 and edge PS")
scene.constraint.geq(Q.x - N3.x, 6.25, description="at least 3 of material between hole 3 and edge QR")
scene.constraint.geq(S.y - N3.y, 6.25, description="at least 3 of material between hole 3 and edge SR")


A rectangular bracket measures 44.9 mm by 27.3 mm. Set up coordinates with the bottom-left corner at the origin P, the 44.9 mm edge running from P along the positive x-direction to Q, and the 27.3 mm edge running from P along the positive y-direction to S; R is the remaining corner. Three holes, each 6.7 mm across, are drilled through it. The centre of the first, N1, is 6.9 mm from edge PS and 8.3 mm from edge PQ. The centre of the second, N2, is 27.5 mm from edge PS and 15.7 mm from edge PQ. The third hole centre N3 is 9.9 mm from edge PQ, and it must sit the same distance from the first hole as from the second. At least 2.6 mm of material must remain between the third hole and every edge of the bracket.

"""Three-hole bracket, third hole equidistant

Oracle formalization for cad_t1_cad_three_hole_0092. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(63)

P, Q, R, S, N1, N2, N3 = scene.add.points(["P", "Q", "R", "S", "N1", "N2", "N3"])

scene.constraint.eq(P.x, 0, description="datum: P is the origin, the datum corner of the bracket (x)")
scene.constraint.eq(P.y, 0, description="datum: P is the origin, the datum corner of the bracket (y)")
scene.constraint.eq(Q.y, 0, description="datum: edge PQ runs along the x-axis")
scene.constraint.gt(Q.x, 1.0, description="datum: the bracket lies in the +x direction from P")
scene.constraint.eq(P.distance(Q), 44.9, description="bracket is 44.9 long along PQ")
scene.constraint.eq(P.distance(S), 27.3, description="bracket is 27.3 wide along PS")
scene.relate.perpendicular(scene.add.line_segment(P, Q), scene.add.line_segment(P, S))
scene.constraint.gt(S.y, 1.0, description="datum: the bracket lies in the +y direction from P")
scene.constraint.eq(R.x, Q.x + S.x - P.x, description="bracket corner R closes the rectangle (x)")
scene.constraint.eq(R.y, Q.y + S.y - P.y, description="bracket corner R closes the rectangle (y)")
scene.constraint.eq(N1.x, 6.9, description="hole 1 is 6.9 from the datum edge PS")
scene.constraint.eq(N1.y, 8.3, description="hole 1 is 8.3 from the datum edge PQ")
scene.constraint.eq(N2.x, 27.5, description="hole 2 is 27.5 from the datum edge PS")
scene.constraint.eq(N2.y, 15.7, description="hole 2 is 15.7 from the datum edge PQ")
scene.constraint.eq(N3.y, 9.9, description="hole 3 is 9.9 from the datum edge PQ")
scene.constraint.eq(N3.distance(N1), N3.distance(N2), description="hole 3 is the same distance from hole 1 as from hole 2")
scene.constraint.geq(N3.y, 5.95, description="at least 2.6 of material between hole 3 and edge PQ")
scene.constraint.geq(N3.x, 5.95, description="at least 2.6 of material between hole 3 and edge PS")
scene.constraint.geq(Q.x - N3.x, 5.95, description="at least 2.6 of material between hole 3 and edge QR")
scene.constraint.geq(S.y - N3.y, 5.95, description="at least 2.6 of material between hole 3 and edge SR")


A circular flange is drilled with 4 bolt holes spaced evenly around a bolt circle that is 25.2 mm across. Set up coordinates with the flange centre at the origin O and the first hole centre H1 on the positive x-axis; number the hole centres H1, H2, H3, H4 going anticlockwise. Each bolt hole is 3.6 mm across. A circular boss of radius 3.8 mm sits at the centre of the flange, and the design requires at least 2.3 mm of material to remain between the boss and every bolt hole.

"""Bolt circle on a flange

Oracle formalization for cad_t2_cad_bolt_circle_0019. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(21)

O, H1, H2, H3, H4 = scene.add.points(["O", "H1", "H2", "H3", "H4"])

scene.constraint.eq(O.x, 0, description="datum: O is the origin, the flange centre (x)")
scene.constraint.eq(O.y, 0, description="datum: O is the origin, the flange centre (y)")
scene.constraint.eq(H1.y, 0, description="datum: the first hole centre H1 lies on the positive x-axis")
scene.constraint.gt(H1.x, 1.0, description="datum: H1 is on the POSITIVE x side of the centre")
bolt_circle = scene.add.circle(O)
scene.constraint.eq(2 * bolt_circle.radius, 25.2, description="the bolt circle is 25.2 across")
scene.relate.point_lies_on(H1, bolt_circle)
scene.relate.point_lies_on(H2, bolt_circle)
scene.relate.point_lies_on(H3, bolt_circle)
scene.relate.point_lies_on(H4, bolt_circle)
scene.constraint.eq(scene.add.angle(H1, O, H2).value, 90, description="holes H1 and H2 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H1, H2), 0.05, description="the holes are numbered anticlockwise, so H2 follows H1")
scene.constraint.eq(scene.add.angle(H2, O, H3).value, 90, description="holes H2 and H3 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H2, H3), 0.05, description="the holes are numbered anticlockwise, so H3 follows H2")
scene.constraint.eq(scene.add.angle(H3, O, H4).value, 90, description="holes H3 and H4 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H3, H4), 0.05, description="the holes are numbered anticlockwise, so H4 follows H3")
scene.constraint.geq(O.distance(H1) - 1.8, 6.1, description="at least 2.3 of material between the central boss and hole H1")
scene.constraint.geq(O.distance(H2) - 1.8, 6.1, description="at least 2.3 of material between the central boss and hole H2")
scene.constraint.geq(O.distance(H3) - 1.8, 6.1, description="at least 2.3 of material between the central boss and hole H3")
scene.constraint.geq(O.distance(H4) - 1.8, 6.1, description="at least 2.3 of material between the central boss and hole H4")

the bolt circle RADIUS is half the stated across-size

evenly spaced means adjacent hole centres subtend 90 degrees at the centre

every hole centre is the same distance from the flange centre

the clearance is measured from the hole EDGE, so it uses the hole radius (half the stated hole size)

the holes are numbered anticlockwise, which fixes the sense of rotation


A circular flange is drilled with 4 bolt holes spaced evenly around a bolt circle that is 35.4 mm across. Set up coordinates with the flange centre at the origin O and the first hole centre H1 on the positive x-axis; number the hole centres H1, H2, H3, H4 going anticlockwise. Each bolt hole is 4.7 mm across. A circular boss of radius 4.2 mm sits at the centre of the flange, and the design requires at least 2.2 mm of material to remain between the boss and every bolt hole.

"""Bolt circle on a flange

Oracle formalization for cad_t2_cad_bolt_circle_0020. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(28)

O, H1, H2, H3, H4 = scene.add.points(["O", "H1", "H2", "H3", "H4"])

scene.constraint.eq(O.x, 0, description="datum: O is the origin, the flange centre (x)")
scene.constraint.eq(O.y, 0, description="datum: O is the origin, the flange centre (y)")
scene.constraint.eq(H1.y, 0, description="datum: the first hole centre H1 lies on the positive x-axis")
scene.constraint.gt(H1.x, 1.0, description="datum: H1 is on the POSITIVE x side of the centre")
bolt_circle = scene.add.circle(O)
scene.constraint.eq(2 * bolt_circle.radius, 35.4, description="the bolt circle is 35.4 across")
scene.relate.point_lies_on(H1, bolt_circle)
scene.relate.point_lies_on(H2, bolt_circle)
scene.relate.point_lies_on(H3, bolt_circle)
scene.relate.point_lies_on(H4, bolt_circle)
scene.constraint.eq(scene.add.angle(H1, O, H2).value, 90, description="holes H1 and H2 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H1, H2), 0.05, description="the holes are numbered anticlockwise, so H2 follows H1")
scene.constraint.eq(scene.add.angle(H2, O, H3).value, 90, description="holes H2 and H3 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H2, H3), 0.05, description="the holes are numbered anticlockwise, so H3 follows H2")
scene.constraint.eq(scene.add.angle(H3, O, H4).value, 90, description="holes H3 and H4 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H3, H4), 0.05, description="the holes are numbered anticlockwise, so H4 follows H3")
scene.constraint.geq(O.distance(H1) - 2.35, 6.4, description="at least 2.2 of material between the central boss and hole H1")
scene.constraint.geq(O.distance(H2) - 2.35, 6.4, description="at least 2.2 of material between the central boss and hole H2")
scene.constraint.geq(O.distance(H3) - 2.35, 6.4, description="at least 2.2 of material between the central boss and hole H3")
scene.constraint.geq(O.distance(H4) - 2.35, 6.4, description="at least 2.2 of material between the central boss and hole H4")


A circular flange is drilled with 4 bolt holes spaced evenly around a bolt circle that is 35.9 mm across. Set up coordinates with the flange centre at the origin O and the first hole centre H1 on the positive x-axis; number the hole centres H1, H2, H3, H4 going anticlockwise. Each bolt hole is 4.6 mm across. A circular boss of radius 3.2 mm sits at the centre of the flange, and the design requires at least 2.3 mm of material to remain between the boss and every bolt hole.

"""Bolt circle on a flange

Oracle formalization for cad_t2_cad_bolt_circle_0021. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(28)

O, H1, H2, H3, H4 = scene.add.points(["O", "H1", "H2", "H3", "H4"])

scene.constraint.eq(O.x, 0, description="datum: O is the origin, the flange centre (x)")
scene.constraint.eq(O.y, 0, description="datum: O is the origin, the flange centre (y)")
scene.constraint.eq(H1.y, 0, description="datum: the first hole centre H1 lies on the positive x-axis")
scene.constraint.gt(H1.x, 1.0, description="datum: H1 is on the POSITIVE x side of the centre")
bolt_circle = scene.add.circle(O)
scene.constraint.eq(2 * bolt_circle.radius, 35.9, description="the bolt circle is 35.9 across")
scene.relate.point_lies_on(H1, bolt_circle)
scene.relate.point_lies_on(H2, bolt_circle)
scene.relate.point_lies_on(H3, bolt_circle)
scene.relate.point_lies_on(H4, bolt_circle)
scene.constraint.eq(scene.add.angle(H1, O, H2).value, 90, description="holes H1 and H2 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H1, H2), 0.05, description="the holes are numbered anticlockwise, so H2 follows H1")
scene.constraint.eq(scene.add.angle(H2, O, H3).value, 90, description="holes H2 and H3 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H2, H3), 0.05, description="the holes are numbered anticlockwise, so H3 follows H2")
scene.constraint.eq(scene.add.angle(H3, O, H4).value, 90, description="holes H3 and H4 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H3, H4), 0.05, description="the holes are numbered anticlockwise, so H4 follows H3")
scene.constraint.geq(O.distance(H1) - 2.3, 5.5, description="at least 2.3 of material between the central boss and hole H1")
scene.constraint.geq(O.distance(H2) - 2.3, 5.5, description="at least 2.3 of material between the central boss and hole H2")
scene.constraint.geq(O.distance(H3) - 2.3, 5.5, description="at least 2.3 of material between the central boss and hole H3")
scene.constraint.geq(O.distance(H4) - 2.3, 5.5, description="at least 2.3 of material between the central boss and hole H4")


A circular flange is drilled with 6 bolt holes spaced evenly around a bolt circle that is 31.7 mm across. Set up coordinates with the flange centre at the origin O and the first hole centre H1 on the positive x-axis; number the hole centres H1, H2, H3, H4, H5, H6 going anticlockwise. Each bolt hole is 4.3 mm across. A circular boss of radius 5.9 mm sits at the centre of the flange, and the design requires at least 2.9 mm of material to remain between the boss and every bolt hole.

"""Bolt circle on a flange

Oracle formalization for cad_t2_cad_bolt_circle_0022. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(26)

O, H1, H2, H3, H4, H5, H6 = scene.add.points(["O", "H1", "H2", "H3", "H4", "H5", "H6"])

scene.constraint.eq(O.x, 0, description="datum: O is the origin, the flange centre (x)")
scene.constraint.eq(O.y, 0, description="datum: O is the origin, the flange centre (y)")
scene.constraint.eq(H1.y, 0, description="datum: the first hole centre H1 lies on the positive x-axis")
scene.constraint.gt(H1.x, 1.0, description="datum: H1 is on the POSITIVE x side of the centre")
bolt_circle = scene.add.circle(O)
scene.constraint.eq(2 * bolt_circle.radius, 31.7, description="the bolt circle is 31.7 across")
scene.relate.point_lies_on(H1, bolt_circle)
scene.relate.point_lies_on(H2, bolt_circle)
scene.relate.point_lies_on(H3, bolt_circle)
scene.relate.point_lies_on(H4, bolt_circle)
scene.relate.point_lies_on(H5, bolt_circle)
scene.relate.point_lies_on(H6, bolt_circle)
scene.constraint.eq(scene.add.angle(H1, O, H2).value, 60, description="holes H1 and H2 are adjacent on an evenly spaced set of 6")
scene.constraint.gt(cross(O, H1, H2), 0.05, description="the holes are numbered anticlockwise, so H2 follows H1")
scene.constraint.eq(scene.add.angle(H2, O, H3).value, 60, description="holes H2 and H3 are adjacent on an evenly spaced set of 6")
scene.constraint.gt(cross(O, H2, H3), 0.05, description="the holes are numbered anticlockwise, so H3 follows H2")
scene.constraint.eq(scene.add.angle(H3, O, H4).value, 60, description="holes H3 and H4 are adjacent on an evenly spaced set of 6")
scene.constraint.gt(cross(O, H3, H4), 0.05, description="the holes are numbered anticlockwise, so H4 follows H3")
scene.constraint.eq(scene.add.angle(H4, O, H5).value, 60, description="holes H4 and H5 are adjacent on an evenly spaced set of 6")
scene.constraint.gt(cross(O, H4, H5), 0.05, description="the holes are numbered anticlockwise, so H5 follows H4")
scene.constraint.eq(scene.add.angle(H5, O, H6).value, 60, description="holes H5 and H6 are adjacent on an evenly spaced set of 6")
scene.constraint.gt(cross(O, H5, H6), 0.05, description="the holes are numbered anticlockwise, so H6 follows H5")
scene.constraint.geq(O.distance(H1) - 2.15, 8.8, description="at least 2.9 of material between the central boss and hole H1")
scene.constraint.geq(O.distance(H2) - 2.15, 8.8, description="at least 2.9 of material between the central boss and hole H2")
scene.constraint.geq(O.distance(H3) - 2.15, 8.8, description="at least 2.9 of material between the central boss and hole H3")
scene.constraint.geq(O.distance(H4) - 2.15, 8.8, description="at least 2.9 of material between the central boss and hole H4")
scene.constraint.geq(O.distance(H5) - 2.15, 8.8, description="at least 2.9 of material between the central boss and hole H5")
scene.constraint.geq(O.distance(H6) - 2.15, 8.8, description="at least 2.9 of material between the central boss and hole H6")

evenly spaced means adjacent hole centres subtend 60 degrees at the centre


A circular flange is drilled with 4 bolt holes spaced evenly around a bolt circle that is 23.5 mm across. Set up coordinates with the flange centre at the origin O and the first hole centre H1 on the positive x-axis; number the hole centres H1, H2, H3, H4 going anticlockwise. Each bolt hole is 4.4 mm across. A circular boss of radius 4.5 mm sits at the centre of the flange, and the design requires at least 2.9 mm of material to remain between the boss and every bolt hole.

"""Bolt circle on a flange

Oracle formalization for cad_t2_cad_bolt_circle_0023. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(20)

O, H1, H2, H3, H4 = scene.add.points(["O", "H1", "H2", "H3", "H4"])

scene.constraint.eq(O.x, 0, description="datum: O is the origin, the flange centre (x)")
scene.constraint.eq(O.y, 0, description="datum: O is the origin, the flange centre (y)")
scene.constraint.eq(H1.y, 0, description="datum: the first hole centre H1 lies on the positive x-axis")
scene.constraint.gt(H1.x, 1.0, description="datum: H1 is on the POSITIVE x side of the centre")
bolt_circle = scene.add.circle(O)
scene.constraint.eq(2 * bolt_circle.radius, 23.5, description="the bolt circle is 23.5 across")
scene.relate.point_lies_on(H1, bolt_circle)
scene.relate.point_lies_on(H2, bolt_circle)
scene.relate.point_lies_on(H3, bolt_circle)
scene.relate.point_lies_on(H4, bolt_circle)
scene.constraint.eq(scene.add.angle(H1, O, H2).value, 90, description="holes H1 and H2 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H1, H2), 0.05, description="the holes are numbered anticlockwise, so H2 follows H1")
scene.constraint.eq(scene.add.angle(H2, O, H3).value, 90, description="holes H2 and H3 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H2, H3), 0.05, description="the holes are numbered anticlockwise, so H3 follows H2")
scene.constraint.eq(scene.add.angle(H3, O, H4).value, 90, description="holes H3 and H4 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H3, H4), 0.05, description="the holes are numbered anticlockwise, so H4 follows H3")
scene.constraint.geq(O.distance(H1) - 2.2, 7.4, description="at least 2.9 of material between the central boss and hole H1")
scene.constraint.geq(O.distance(H2) - 2.2, 7.4, description="at least 2.9 of material between the central boss and hole H2")
scene.constraint.geq(O.distance(H3) - 2.2, 7.4, description="at least 2.9 of material between the central boss and hole H3")
scene.constraint.geq(O.distance(H4) - 2.2, 7.4, description="at least 2.9 of material between the central boss and hole H4")


A circular flange is drilled with 5 bolt holes spaced evenly around a bolt circle that is 28 mm across. Set up coordinates with the flange centre at the origin O and the first hole centre H1 on the positive x-axis; number the hole centres H1, H2, H3, H4, H5 going anticlockwise. Each bolt hole is 3.5 mm across. A circular boss of radius 5.6 mm sits at the centre of the flange, and the design requires at least 2.8 mm of material to remain between the boss and every bolt hole.

"""Bolt circle on a flange

Oracle formalization for cad_t2_cad_bolt_circle_0024. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(23)

O, H1, H2, H3, H4, H5 = scene.add.points(["O", "H1", "H2", "H3", "H4", "H5"])

scene.constraint.eq(O.x, 0, description="datum: O is the origin, the flange centre (x)")
scene.constraint.eq(O.y, 0, description="datum: O is the origin, the flange centre (y)")
scene.constraint.eq(H1.y, 0, description="datum: the first hole centre H1 lies on the positive x-axis")
scene.constraint.gt(H1.x, 1.0, description="datum: H1 is on the POSITIVE x side of the centre")
bolt_circle = scene.add.circle(O)
scene.constraint.eq(2 * bolt_circle.radius, 28, description="the bolt circle is 28 across")
scene.relate.point_lies_on(H1, bolt_circle)
scene.relate.point_lies_on(H2, bolt_circle)
scene.relate.point_lies_on(H3, bolt_circle)
scene.relate.point_lies_on(H4, bolt_circle)
scene.relate.point_lies_on(H5, bolt_circle)
scene.constraint.eq(scene.add.angle(H1, O, H2).value, 72, description="holes H1 and H2 are adjacent on an evenly spaced set of 5")
scene.constraint.gt(cross(O, H1, H2), 0.05, description="the holes are numbered anticlockwise, so H2 follows H1")
scene.constraint.eq(scene.add.angle(H2, O, H3).value, 72, description="holes H2 and H3 are adjacent on an evenly spaced set of 5")
scene.constraint.gt(cross(O, H2, H3), 0.05, description="the holes are numbered anticlockwise, so H3 follows H2")
scene.constraint.eq(scene.add.angle(H3, O, H4).value, 72, description="holes H3 and H4 are adjacent on an evenly spaced set of 5")
scene.constraint.gt(cross(O, H3, H4), 0.05, description="the holes are numbered anticlockwise, so H4 follows H3")
scene.constraint.eq(scene.add.angle(H4, O, H5).value, 72, description="holes H4 and H5 are adjacent on an evenly spaced set of 5")
scene.constraint.gt(cross(O, H4, H5), 0.05, description="the holes are numbered anticlockwise, so H5 follows H4")
scene.constraint.geq(O.distance(H1) - 1.75, 8.4, description="at least 2.8 of material between the central boss and hole H1")
scene.constraint.geq(O.distance(H2) - 1.75, 8.4, description="at least 2.8 of material between the central boss and hole H2")
scene.constraint.geq(O.distance(H3) - 1.75, 8.4, description="at least 2.8 of material between the central boss and hole H3")
scene.constraint.geq(O.distance(H4) - 1.75, 8.4, description="at least 2.8 of material between the central boss and hole H4")
scene.constraint.geq(O.distance(H5) - 1.75, 8.4, description="at least 2.8 of material between the central boss and hole H5")

evenly spaced means adjacent hole centres subtend 72 degrees at the centre


A circular flange is drilled with 4 bolt holes spaced evenly around a bolt circle that is 25.7 mm across. Set up coordinates with the flange centre at the origin O and the first hole centre H1 on the positive x-axis; number the hole centres H1, H2, H3, H4 going anticlockwise. Each bolt hole is 4.6 mm across. A circular boss of radius 4.1 mm sits at the centre of the flange, and the design requires at least 3 mm of material to remain between the boss and every bolt hole.

"""Bolt circle on a flange

Oracle formalization for cad_t2_cad_bolt_circle_0025. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(22)

O, H1, H2, H3, H4 = scene.add.points(["O", "H1", "H2", "H3", "H4"])

scene.constraint.eq(O.x, 0, description="datum: O is the origin, the flange centre (x)")
scene.constraint.eq(O.y, 0, description="datum: O is the origin, the flange centre (y)")
scene.constraint.eq(H1.y, 0, description="datum: the first hole centre H1 lies on the positive x-axis")
scene.constraint.gt(H1.x, 1.0, description="datum: H1 is on the POSITIVE x side of the centre")
bolt_circle = scene.add.circle(O)
scene.constraint.eq(2 * bolt_circle.radius, 25.7, description="the bolt circle is 25.7 across")
scene.relate.point_lies_on(H1, bolt_circle)
scene.relate.point_lies_on(H2, bolt_circle)
scene.relate.point_lies_on(H3, bolt_circle)
scene.relate.point_lies_on(H4, bolt_circle)
scene.constraint.eq(scene.add.angle(H1, O, H2).value, 90, description="holes H1 and H2 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H1, H2), 0.05, description="the holes are numbered anticlockwise, so H2 follows H1")
scene.constraint.eq(scene.add.angle(H2, O, H3).value, 90, description="holes H2 and H3 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H2, H3), 0.05, description="the holes are numbered anticlockwise, so H3 follows H2")
scene.constraint.eq(scene.add.angle(H3, O, H4).value, 90, description="holes H3 and H4 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H3, H4), 0.05, description="the holes are numbered anticlockwise, so H4 follows H3")
scene.constraint.geq(O.distance(H1) - 2.3, 7.1, description="at least 3 of material between the central boss and hole H1")
scene.constraint.geq(O.distance(H2) - 2.3, 7.1, description="at least 3 of material between the central boss and hole H2")
scene.constraint.geq(O.distance(H3) - 2.3, 7.1, description="at least 3 of material between the central boss and hole H3")
scene.constraint.geq(O.distance(H4) - 2.3, 7.1, description="at least 3 of material between the central boss and hole H4")


A circular flange is drilled with 4 bolt holes spaced evenly around a bolt circle that is 30.2 mm across. Set up coordinates with the flange centre at the origin O and the first hole centre H1 on the positive x-axis; number the hole centres H1, H2, H3, H4 going anticlockwise. Each bolt hole is 3.9 mm across. A circular boss of radius 4.8 mm sits at the centre of the flange, and the design requires at least 2.3 mm of material to remain between the boss and every bolt hole.

"""Bolt circle on a flange

Oracle formalization for cad_t2_cad_bolt_circle_0026. Every constraint below corresponds to one
statement in the problem text; the datum constraints fix the coordinate frame
the text describes, and the inequality constraints encode the discrete choices
the text makes explicit (which side, which branch).
"""
from pygeox import GeoScene

def cross(A, B, P):
    """z-component of (B-A) x (P-A). Positive iff P lies to the LEFT of the
    directed line A->B. Used to state 'above', 'on the far side', 'anticlockwise'
    without any appeal to a picture."""
    return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x)

def dot(A, B, C, D):
    """(B-A) . (D-C). Positive iff the two directions point the same way."""
    return (B.x - A.x) * (D.x - C.x) + (B.y - A.y) * (D.y - C.y)

scene = GeoScene(25)

O, H1, H2, H3, H4 = scene.add.points(["O", "H1", "H2", "H3", "H4"])

scene.constraint.eq(O.x, 0, description="datum: O is the origin, the flange centre (x)")
scene.constraint.eq(O.y, 0, description="datum: O is the origin, the flange centre (y)")
scene.constraint.eq(H1.y, 0, description="datum: the first hole centre H1 lies on the positive x-axis")
scene.constraint.gt(H1.x, 1.0, description="datum: H1 is on the POSITIVE x side of the centre")
bolt_circle = scene.add.circle(O)
scene.constraint.eq(2 * bolt_circle.radius, 30.2, description="the bolt circle is 30.2 across")
scene.relate.point_lies_on(H1, bolt_circle)
scene.relate.point_lies_on(H2, bolt_circle)
scene.relate.point_lies_on(H3, bolt_circle)
scene.relate.point_lies_on(H4, bolt_circle)
scene.constraint.eq(scene.add.angle(H1, O, H2).value, 90, description="holes H1 and H2 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H1, H2), 0.05, description="the holes are numbered anticlockwise, so H2 follows H1")
scene.constraint.eq(scene.add.angle(H2, O, H3).value, 90, description="holes H2 and H3 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H2, H3), 0.05, description="the holes are numbered anticlockwise, so H3 follows H2")
scene.constraint.eq(scene.add.angle(H3, O, H4).value, 90, description="holes H3 and H4 are adjacent on an evenly spaced set of 4")
scene.constraint.gt(cross(O, H3, H4), 0.05, description="the holes are numbered anticlockwise, so H4 follows H3")
scene.constraint.geq(O.distance(H1) - 1.95, 7.1, description="at least 2.3 of material between the central boss and hole H1")
scene.constraint.geq(O.distance(H2) - 1.95, 7.1, description="at least 2.3 of material between the central boss and hole H2")
scene.constraint.geq(O.distance(H3) - 1.95, 7.1, description="at least 2.3 of material between the central boss and hole H3")
scene.constraint.geq(O.distance(H4) - 1.95, 7.1, description="at least 2.3 of material between the central boss and hole H4")