6
\$\begingroup\$

I've written the following module to generate arbitrary triangles based on a subset of lengths and angles, like what https://www.calculator.net/triangle-calculator.html provides. It works well enough but as-written it's fairly repetitive. I'm new to OpenSCAD so I'd love some feedback if there are cleaner ways to express this (or obviously if there are bugs/edge cases I've missed).

// Creates a 2D triangle with the given sides and/or angles.
// Any three parameters can be used to describe the triangle, e.g.
// a=3,b=4,c=5; a=3,b=4,c_angle=90; and a=3,b_angle=53.13,c_angle=90
// all describe the same triangle.
// Side c runs along the x axis, with side a leaving the origin at a_angle.
// Reference: https://www.calculator.net/triangle-calculator.html
module triangle(a=0,b=0,c=0,a_angle=0,b_angle=0,c_angle=0) {
 assert(a_angle==a_angle && b_angle==b_angle && c_angle==c_angle,
 "Invalid triangle: impossible angles");
 
 // returns c
 function shared_angle(a, b, c_angle) = sqrt(pow(b,2)+pow(a,2)-2*b*a*cos(c_angle));
 // returns c_angle
 function opposing_angle(a, a_angle, b) = asin(b*sin(a_angle)/a);
 // returns angles A, B, C if they sum to 180
 // if one angle is unset (0) it will be set to the difference of the other two
 function triangle_angles(a, b, c) =
 let (
 a = a > 0 ? a : assert(b!=0 && c!=0, "Insufficient angles") 180 - b - c,
 b = b > 0 ? b : assert(a!=0 && c!=0, "Insufficient angles") 180 - a - c,
 c = c > 0 ? c : assert(a!=0 && b!=0, "Insufficient angles") 180 - a - b
 )
 assert(a + b + c == 180, "Invalid triangle: impossible angles")
 [a,b,c];
 // returns b
 function angle_ratio(a, angle_a, angle_b) = a*sin(angle_b)/sin(angle_a);
 // Three Sides
 if (a>0 && b>0 && c>0) {
 assert(a_angle==0 && b_angle==0 && c_angle==0, "Too many arguments");
 let ( a_angle = acos((pow(b,2)+pow(c,2)-pow(a,2))/(2*b*c)) ) {
 assert(a_angle==a_angle, "Invalid triangle: impossible lengths");
 assert(sin(a_angle)!= 0, "Invalid triangle: colinear");
 polygon(points = [[0, 0], [c, 0], [b * cos(a_angle), b * sin(a_angle)]]);
 }
 // Shared Angle
 } else if (a>0 && b>0 && c_angle>0) {
 assert(c==0 && a_angle==0 && b_angle==0, "Too many arguments");
 triangle(a,b,shared_angle(a,b,c_angle));
 } else if (a>0 && c>0 && b_angle>0) {
 assert(b==0 && a_angle==0 && c_angle==0, "Too many arguments");
 triangle(a,shared_angle(a,c,b_angle),c);
 } else if (b>0 && c>0 && a_angle>0) {
 assert(a==0 && b_angle==0 && c_angle==0, "Too many arguments");
 triangle(shared_angle(b,c,a_angle),b,c);
 // Opposing Angle
 } else if (a>0 && a_angle>0 && b>0) {
 assert(c==0 && c_angle==0 && b_angle==0, "Too many arguments");
 triangle(a=a,b=b,c_angle=opposing_angle(a,a_angle,b));
 } else if (a>0 && a_angle>0 && c>0) {
 assert(b==0 && b_angle==0 && c_angle==0, "Too many arguments");
 triangle(a=a,c=c,b_angle=opposing_angle(a,a_angle,c));
 } else if (b>0 && b_angle>0 && a>0) {
 assert(c==0 && c_angle==0 && a_angle==0, "Too many arguments");
 triangle(a=a,b=b,c_angle=opposing_angle(b,b_angle,a));
 } else if (b>0 && b_angle>0 && c>0) {
 assert(a==0 && a_angle==0 && c_angle==0, "Too many arguments");
 triangle(a=a,c=c,a_angle=opposing_angle(b,b_angle,c));
 } else if (c>0 && c_angle>0 && a>0) {
 assert(b==0 && b_angle==0 && a_angle==0, "Too many arguments");
 triangle(a=a,c=c,b_angle=opposing_angle(c,c_angle,a));
 } else if (c>0 && c_angle>0 && b>0) {
 assert(a == 0 && a_angle == 0 && b_angle == 0, "Too many arguments");
 triangle(b = b, c = c, a_angle = opposing_angle(c, c_angle, b));
 // Two+ Angles
 } else if (a>0 && b==0 && c==0) {
 angles = triangle_angles(a_angle, b_angle, c_angle);
 triangle(a=a, b=angle_ratio(a,angles[0],angles[1]), c=angle_ratio(a,angles[0],angles[2]));
 } else if (b>0 && a==0 && c==0) {
 angles = triangle_angles(a_angle, b_angle, c_angle);
 triangle(a=angle_ratio(b,angles[1],angles[0]), b=b, c=angle_ratio(b,angles[1],angles[2]));
 } else if (c>0 && a==0 && b==0) {
 angles = triangle_angles(a_angle, b_angle, c_angle);
 triangle(a=angle_ratio(c,angles[2],angles[0]), b=angle_ratio(c,angles[2],angles[1]), c=c);
 } else {
 assert(false, "Insufficient arguments");
 }
}

Like the calculator, only three arguments are needed to specify a triangle. So for example these all define the same shape:

triangle(a=3, b=4, c=5);
triangle(a=3, b=4, c_angle=90);
triangle(a=3, b_angle=53.13, c_angle=90);
asked May 28, 2021 at 20:11
\$\endgroup\$
3
  • \$\begingroup\$ Hello, probably I am wrong but would it be possible define a triangle with just two sides and the angle between them (I don't know openscad) ? \$\endgroup\$ Commented Jun 3, 2021 at 7:42
  • \$\begingroup\$ Right, that's the idea. Any three arguments are sufficient. \$\endgroup\$ Commented Jun 3, 2021 at 17:34
  • \$\begingroup\$ I read again your post, please ignore my previous question and thanks for the added details. \$\endgroup\$ Commented Jun 3, 2021 at 20:38

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.