tangentes a un círculo con OpenSCAD
trabajar con sucedáneos de curvas
He diseñando una pieza que básicamente es un cilindro unido a un cubo con la transformación hull() de OpenSCAD. Si volteo la pieza sobre su lado izquierdo la podré fabricar sin necesidad de soportes, pero desconozco el ángulo de giro.
El siguiente gráfico representa el problema:
radio = 25;
ancho = 15;
alto = 10;
x = 15;
y = 40;
rotate([0,0,¿cuánto?])
hull(){
#circle(radio);
#translate([x, y])
square([ancho, alto]);
}
Generalizando, se puede calcular la tangente a dos círculos conocidos. En el caso particular de que uno de los círculos tenga radio=0 tendremos resuelto el problema anterior: tangente a un círculo que pasa por un punto.
El segmento H que une los dos círculos mide raiz(P2+Q2 ) y forma con la horizontal un ángulo arctan(Q/P). A su vez es la bisectriz del ángulo formado por las tangentes T y T'. El ángulo entre H y T será entonces arcsen( (R-r) / H ).
// planteamiento: calcular los ángulos de las tangentes a dos círculos
// parámetros
R = 25 ;
r = 12 ;
p = 35 ;
q = 40 ;
// cálculo de los ángulos de tangente (para p<0 sumamos 180º)
alfa = atan(q/p) + asin((R-r)/sqrt(pow(p, 2)+pow(q, 2))) + (p<0?180:0);
beta = atan(q/p) - asin((R-r)/sqrt(pow(p, 2)+pow(q, 2))) + (p<0?180:0);
//---------------
circle(R);
translate([p, q])
circle(r);
//---------------
// trazar una tangente calculando el punto de contacto (depende de alfa)
color("red")
translate([R*cos(alfa-90), R*sin(alfa-90)])
rotate([0,0,alfa])
raya();
// el punto de contacto de la otra tangente depende de beta
color("blue")
translate([R*cos(beta+90), R*sin(beta+90)])
rotate([0,0,beta])
raya();
module raya() {
translate([-15, -.25])
square([75, .50]);
}
Ahora llega la cruda realidad: OpenSCAD no trabaja con curvas, sino que las simula más o menos bien con rectas y planos (según trabajemos en 2 o 3D). Es posible que la tangente a nuestro círculo imaginario no llegue a tocar el polígono correspondiente. Cuando procesamos nuestro diseño con un fileteador como Slic3r cabe la posibilidad de que la pieza no sea bien interpretada y el resultado final tenga problemas. Gráficamente nos encontramos con esto:
...
//---------------
$fn=8;
circle(R);
translate([p, q])
circle(r);
//---------------
...
Los lados del polígono no están puestos de cualquier manera: OpenSCAD empieza a dibujar a partir del punto de coordenadas (radio, 0) en sentido antihorario. Conocemos el ángulo de la tangente, así que si giramos el polígono angulo-90º se estará empezando a dibujar por el punto de tangencia. El siguiente código sería para apañar la tangente roja, pero entonces dejamos la azul peor:
...
//---------------
$fn=8;
rotate([0,0,alfa-90]);
circle(R);
translate([p, q])
rotate([0,0,alfa-90]);
circle(r);
//---------------
...
Si necesitamos las dos tangentes correctamente unidas la solución puede ser hacer una pareja de círculos rotados para la tangente roja, fundidos con hull() con otra pareja girada para la tangente azul:
...
//---------------
$fn=8;
hull() {
rotate([0,0,alfa-90])
circle(R);
rotate([0,0,beta-90])
circle(R);
}
translate([p, q])
hull() {
rotate([0,0,alfa-90])
circle(r);
rotate([0,0,beta-90])
circle(r);
}
//---------------
...
Y ahora volvemos al planteamiento inicial: consideramos que el circulo desplazado tiene radio=0, y está en la esquina superior izquierda del rectángulo. Esta será la solución:
radio = 25;
ancho = 15;
alto = 10;
x = 15;
y = 40;
beta = atan((y+alto)/x)
- asin(radio/sqrt(pow(x, 2)+pow(y+alto, 2)));
rotate([0,0,180-beta])
hull() {
rotate([0, 0, beta+90])
#circle(radio);
#translate([x, y])
square([ancho, alto]);
}
La rotación resaltada en rojo garantiza que la línea de apoyo va a ser matemáticamente horizontal. Con un valor de $fn=6 se puede ver que esa rotación es necesaria, pero si el círculo se hace con un valor $fn tal que se ve cabalmente redondo no hará falta dicha rotación, pero tampoco come pan.