//
// NopSCADlib Copyright Chris Palmer 2021
// nop.head@gmail.com
// hydraraptor.blogspot.com
//
// This file is part of NopSCADlib.
//
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with NopSCADlib.
// If not, see <https://www.gnu.org/licenses/>.
//
//! Potentiometers and rotary encoders
include <../utils/core/core.scad>
use <../utils/rounded_cylinder.scad>
use <../utils/round.scad>
use <../utils/thread.scad>

pot_nut_t = 2;
pot_proud = 0.3;
spigot_r = 0.5;
tab = [3.2, 0.5];

function pot_body(type)     = type[1];  //! Body diameter or width & depth, height and corner radius
function pot_face(type)     = type[2];  //! Faceplate rib width, plate depth and plate height
function pot_wafer(type)    = type[3];  //! Width, diameter and thickness of the track wafer plus true if curved
function pot_gangs(type)    = type[4];  //! Number of gangs for mult-gang pot
function pot_thread_d(type) = type[5];  //! Nomininal thread diameter
function pot_thread_p(type) = type[6];  //! Thread pritch
function pot_thread_h(type) = type[7];  //! Height of threaded part
function pot_boss_d(type)   = type[8];  //! Boss diameter
function pot_boss_h(type)   = type[9];  //! Boss height
function pot_spigot(type)   = type[10]; //! Spigot width, length and height above the boss
function pot_spigot_x(type) = type[11]; //! Spigot offset from the shaft centre
function pot_shaft(type)    = type[12]; //! Diameter, flat diameter, length and flat/slot length and colour. If flat diameter is less than the radius then it is a slot width
function pot_neck(type)     = type[13]; //! Diameter and length of the shaft neck
function pot_nut(type)      = type[14]; //! Across flat diameter and thickness of the nut
function pot_washer(type)   = type[15]; //! Outside diameter and thickness of the washer

function pot_size(type) = let(d = pot_body(type)) len(d) > 3 ? [d.x , d.y, d.z] : [d.x, d.x, d.y]; //! Get pot body dimensions

function pot_z(type, washer = true) = pot_thread_h(type) - pot_nut(type)[1] - pot_proud - (washer ? pot_washer(type)[1] : 0); //! Ideal distance behind panel surface to get the nut and washer on comfortably
function pot_spigot_r(type) = let(sp = pot_spigot(type)) sp.x > 2 * spigot_r ? spigot_r : 0;

module pot_nut(type, washer = true) { //! Draw the nut for a potentiometer and possibly a washer
    nut = pot_nut(type);
    washer = washer ? pot_washer(type) : false;
    nut_z = washer ? washer[1] : 0;
    thread_d = pot_thread_d(type);
    vflip() explode(23, explode_children = true) {
        if(washer)
            color(washer[2])
                linear_extrude(washer[1])
                    difference() {
                        circle(d = washer.x);

                        circle(d =  thread_d);

                        serations = washer[3];
                        if(serations)
                            for(i = [1 : serations])
                                rotate(i * 360 / serations)
                                    translate([thread_d / 2, 0])
                                        square([(washer.x - thread_d) / 2, PI * thread_d / (2 * serations)], center = true);
                    }

        if(nut)
            color(nut[2])
                translate_z(nut_z + exploded() * 10) {
                    linear_extrude(nut[1])
                        difference() {
                            circle(d = nut.x / cos(30), $fn = 6);

                            circle(d =  thread_d);
                        }

                    if(show_threads && exploded())
                        female_metric_thread(thread_d, pot_thread_p(type), nut[1], center = false, colour = nut[2]);
                }
    }
}

module potentiometer(type, thickness = 3, shaft_length = undef, value = false) {//! Draw a potentiometer with nut spaced by specified thickness
    bh = pot_boss_h(type);
    s = pot_size(type);
    face =  pot_face(type);
    wafer =  pot_wafer(type);
    wafer_z = wafer? wafer.z : 0;
    round = len(pot_body(type)) < 4;
    dia_cast_colour = grey(60);
    thread_d = pot_thread_d(type);
    thread_h = pot_thread_h(type);
    shaft = pot_shaft(type);
    vitamin(str("potentiometer(", type[0], "): ", slice(type[0], start = -8) != "_encoder" ? "Potentiometer " : "", value ? value : type[0]));

    color(dia_cast_colour) {
        // Boss
        if(bh)
            cylinder(d = pot_boss_d(type), h = bh);

        if(face) {
            if(face.x) {
                linear_extrude(face.z)
                    square([face.x, face.y], center = true);

                linear_extrude(bh)
                    difference() {
                        square([face.x, face.y], center = true);

                        square([face.x - 2 * face.z, s.x], center = true);
                    }
            }
            translate_z(bh - face.z)
                linear_extrude(face.z)
                    intersection() {
                        circle(d = s.x - eps);

                        difference() {
                            square([s.x + eps, face.y], center = true);

                            if(face.x)
                                square([face.x - 2 * face.z, s.x], center = true);
                        }
                    }
        }

        // spigot
        x = pot_spigot_x(type);
        sp = pot_spigot(type);
        if(x)
            translate([x, 0, bh])
                vflip()
                    rounded_rectangle(sp + [0, 0, bh], pot_spigot_r(type));
        // thread
        vflip()
            if(show_threads)
                male_metric_thread(thread_d, pot_thread_p(type), thread_h, center = false, bot = 0, colour = dia_cast_colour);
            else
                cylinder(d = thread_d, h = pot_thread_h(type));
    }

    d = pot_body(type);
    fz = face ? face.z : 0;
    gap = face ? face.z + tab[1] : 0;
    total_h = s.z - bh;
    gangs = pot_gangs(type);
    gang_h = (total_h - (gangs - 1) * gap) / gangs;
    pitch = gang_h + gap;
    for(i = [0 : gangs - 1])
        translate_z(bh + i * pitch) {
            // Wafer that carries the track and contacts
            if(wafer)
                color("sienna") {
                    linear_extrude(wafer.z) round(wafer[3] ? 1 : 0) {
                        if(round)
                            circle(d = s.x - eps);
                        else
                            rounded_square([s.x, s.y], d[3]);

                        intersection() {
                            translate([0, -s.y / 2])
                                square([wafer.x, (wafer.y - s.y) * 2], center = true);

                            if(wafer[3])
                                circle(wafer.y - s.y / 2);
                            else
                                square(100, center = true);
                        }
                    }
                }

            color(silver) {
                // Body
                translate_z(wafer_z)
                    if(round)
                        rounded_cylinder(r = s.x / 2, r2 = d[2], h = gang_h - wafer_z);
                    else
                        rounded_rectangle([s.x, s.y, gang_h - wafer_z], d[3]);

                // Make tabs that hold the face on
                if(face) {
                    translate_z(-tab[1] - fz)
                        linear_extrude(face.z + tab[1] + wafer_z)
                            intersection() {
                                circle(d = s.x);

                                for(x = [-1, 1], y = [-1, 1], a = y * 90 + 90 + x * 30)
                                    rotate(a)
                                        translate([s.x / 2, 0])
                                            slot(r = tab.x / 2, l = (s.x - pot_boss_d(type)) / 2 - tab.x / 2, h = 0);
                            }
                }
            }

            // Face plate between sections
            if(face && i) {
                color(dia_cast_colour)
                    translate_z(-fz)
                        linear_extrude(fz)
                            intersection() {
                                circle(d = s.x - eps);

                            square([s.x + eps, face.y], center = true);
                         }

                color(shaft[4])
                    vflip()
                        cylinder(d = shaft.x, h = gap);
            }
        }

    // Shaft
    color(shaft[4])
        translate_z(-thread_h) vflip() {
                shaft_z = is_undef(shaft_length) ? shaft.z : min(shaft_length, shaft.z);
                flat_h = shaft[3] - (shaft.z - shaft_z);
                plain = shaft_z - flat_h;
                neck = pot_neck(type);
                neck_h = neck[1];

                if(neck_h)
                    cylinder(d = neck.x, h = neck_h);

                if(plain - neck_h > 0)
                    translate_z(neck_h)
                        cylinder(d = shaft.x, h = plain - neck_h);

                if(flat_h)
                    translate_z(plain)
                        linear_extrude(flat_h)
                            difference() {
                                circle(d = shaft.x);

                                if(shaft.y > shaft.x / 2)
                                    translate([0, shaft.x / 2])
                                        square([shaft.x, 2 * (shaft.x - shaft.y)], center = true);
                                else
                                    if(shaft.y)
                                        square([shaft.y, shaft.x + 1], center = true);
                            }
            }
}
