# %% [markdown]
# # Ring for the new Philips Avent camera base
# 
# Remix of the Ring from [Printables 270294](https://www.printables.com/model/270294-bracket-for-philips-avent-babycam/files),
# replacing `original_ring-CHANGE-ME.stl` (the no-text ring). Bolt, Jaw and Saucer stay as they are.
# 
# The original ring clamps the old camera's wide, flat base under its rounded top bead (inner Ø86 mm).
# The new camera base is Ø71 x 13.5 mm (see the photos): too narrow for the bead to catch, and it sticks
# out above the ring.
# 
# In the assembly coordinates of the source STLs (saucer face at z = 1):
# 
# * the threaded part below `z_cut` is kept, so it still screws onto the original saucer;
# * the bead is cut off and replaced by a straight wall up to the top of the base and a flat flange that
#   reaches `overlap` mm over the base edge; the bore steps into the thread with a 45° cone;
# * a short skirt under the flange centres the base, so that overlap is the same all round.
# 
# The source is the original ring *with* text from `../Phillips Avent Connected adjustable`, and the
# text is filled with the same sleeve as in `no_text.ipynb`: the no-text STL (= `original_ring-CHANGE-ME.stl`)
# has a few sliver triangles on the sleeve seam that OpenSCAD 2021's CGAL refuses to boolean with
# (`e_below != SHalfedge_handle()`). Below `z_cut` the result is the same as that STL.
# 
# The thread leaves several mm of travel either way, which takes up any error in `base_h`.
# 
# The STL is written **upside down, flange on the bed**: the flange is a 15 mm wide inward overhang
# the other way round. OpenSCAD 2021 (CGAL) takes about a minute on this mesh.

# %%
from pathlib import Path

from solid2 import cylinder, import_stl, polygon, rotate, rotate_extrude, translate

from jupyterscad import view_stl

# %%
# new camera base, measured (photos in this folder)
base_d = 71.0  # diameter
base_h = 13.5  # height
saucer_top = 1.0  # z of the saucer face the base stands on

# source ring, measured from the mesh
r_out = 50.635  # outer cylinder
r_crest = 46.2  # just inside the thread crests (r = 46.26)
r_bore = 47.7  # just outside the thread roots (r = 47.66)
z_cut = 5.0  # the thread runs out between z = 4.3 and 5.5; the bead above it goes

# text fill below z_cut, as in no_text.ipynb (text engraved ~0.4 mm into the outer band from z = 0.64)
sleeve_r = (48.5, 50.61)  # clear of the thread roots / just inside the outer cylinder
sleeve_z = 0.6

# new top
overlap = 3.0  # how far the flange reaches over the base edge
fit = 0.5  # radial clearance between base and skirt
flange_t = 3.0  # flange thickness
skirt_h = 3.0  # skirt length below the flange
skirt_t = 2.0  # skirt wall
lead = 0.8  # lead-in chamfer on the skirt mouth
chamfer = 1.0  # 45° on the outer and hole edges of the flange top

z_flange = saucer_top + base_h  # flange underside = top of the base
z_top = z_flange + flange_t

# %%
def top_profile():
    """(r, z) outline of the new wall + flange + skirt, for rotate_extrude."""
    r_hole = base_d / 2 - overlap
    r_skirt = base_d / 2 + fit
    return [
        (sleeve_r[0], sleeve_z),  # text-fill sleeve, inside the kept wall
        (sleeve_r[1], sleeve_z),
        (sleeve_r[1], z_cut),
        (r_out, z_cut),
        (r_out, z_top - chamfer),
        (r_out - chamfer, z_top),
        (r_hole + chamfer, z_top),
        (r_hole, z_top - chamfer),
        (r_hole, z_flange),
        (r_skirt, z_flange),
        (r_skirt, z_flange - skirt_h + lead),
        (r_skirt + lead, z_flange - skirt_h),
        (r_skirt + skirt_t, z_flange - skirt_h),
        (r_skirt + skirt_t, z_flange),
        (r_bore, z_flange),
        (r_bore, z_cut + (r_bore - r_crest)),  # 45° cone down to the thread crests
        (r_crest, z_cut),
        (sleeve_r[0], z_cut),
    ]


def ring_new_camera(src):
    kept = import_stl(src, convexity=6) - translate([0, 0, z_cut])(cylinder(r=r_out + 5, h=30))
    ring = kept + rotate_extrude(convexity=4, _fn=360)(polygon(top_profile()))
    # print orientation: flange on the bed at z = 0
    return translate([0, 0, z_top])(rotate([180, 0, 0])(ring))


def render(shape, outfile):
    stem = Path(outfile).with_suffix("")
    shape.save_as_scad(filename=str(stem) + ".scad")
    shape.save_as_stl(filename=str(stem) + ".stl")
    return view_stl(str(stem) + ".stl")

# %%
# relative import path, resolved from the .scad in this folder
src = "../Phillips Avent Connected adjustable/Joker_G Nanny Cam Bracket Ring.stl"
render(ring_new_camera(src), "ring_new_camera.scad")

# %% [markdown]
# ## Fit gauge
# 
# A quick print (~6 cm³, 15 mm tall) to check the measurements before printing the full ring. It is the flange
# hole and skirt of the ring, with a narrow flange and three legs reaching down to the saucer face.
# 
# 1. **Hole**: it has to slide over the camera body, as the ring will.
# 2. **Skirt**: the top edge of the base should drop in with a little play, centred.
# 3. **Height**: with the base on the saucer (or a table) and the gauge resting on the base, the legs
#    should just touch the surface. A gap under the legs = base taller than `base_h` by that gap; the
#    gauge rocking on its legs = base lower.

# %%
gauge_r = 41.0  # outer radius of the narrow flange; the legs sit out here
gauge_t = 1.6  # flange thickness, enough to keep its shape
leg_w = 15  # leg width [deg]


def fit_gauge():
    r_hole = base_d / 2 - overlap
    r_skirt = base_d / 2 + fit
    z_t = z_flange + gauge_t
    flange = [
        (r_hole, z_t),
        (r_hole, z_flange),
        (r_skirt, z_flange),
        (r_skirt, z_flange - skirt_h + lead),
        (r_skirt + lead, z_flange - skirt_h),
        (r_skirt + skirt_t, z_flange - skirt_h),
        (r_skirt + skirt_t, z_flange),
        (gauge_r, z_flange),
        (gauge_r, z_t),
    ]
    # legs from the flange underside down to the saucer face, overlapping the skirt
    r_leg = r_skirt + skirt_t - 0.5
    leg_profile = [
        (r_leg, saucer_top),
        (gauge_r, saucer_top),
        (gauge_r, z_flange + 0.1),
        (r_leg, z_flange + 0.1),
    ]
    leg = rotate_extrude(angle=leg_w, convexity=2, _fn=360)(polygon(leg_profile))
    gauge = rotate_extrude(convexity=4, _fn=360)(polygon(flange))
    for a in (0, 120, 240):
        gauge += rotate([0, 0, a - leg_w / 2])(leg)
    # same print orientation as the ring: flange on the bed
    return translate([0, 0, z_t])(rotate([180, 0, 0])(gauge))

# %%
render(fit_gauge(), "fit_gauge.scad")

# %%



