diff --git a/geometry.scad b/geometry.scad index 561e6a2..68263c3 100644 --- a/geometry.scad +++ b/geometry.scad @@ -334,414 +334,6 @@ function line_from_points(points, fast=false, eps=EPSILON) = -// Section: 2D Triangles - - -// Function: law_of_cosines() -// Usage: -// C = law_of_cosines(a, b, c); -// c = law_of_cosines(a, b, C); -// Topics: Geometry, Triangles -// Description: -// Applies the Law of Cosines for an arbitrary triangle. Given three side lengths, returns the -// angle in degrees for the corner opposite of the third side. Given two side lengths, and the -// angle between them, returns the length of the third side. -// Figure(2D): -// stroke([[-50,0], [10,60], [50,0]], closed=true); -// color("black") { -// translate([ 33,35]) text(text="a", size=8, halign="center", valign="center"); -// translate([ 0,-6]) text(text="b", size=8, halign="center", valign="center"); -// translate([-22,35]) text(text="c", size=8, halign="center", valign="center"); -// } -// color("blue") { -// translate([-37, 6]) text(text="A", size=8, halign="center", valign="center"); -// translate([ 9,51]) text(text="B", size=8, halign="center", valign="center"); -// translate([ 38, 6]) text(text="C", size=8, halign="center", valign="center"); -// } -// Arguments: -// a = The length of the first side. -// b = The length of the second side. -// c = The length of the third side. -// C = The angle in degrees of the corner opposite of the third side. -function law_of_cosines(a, b, c, C) = - // Triangle Law of Cosines: - // c^2 = a^2 + b^2 - 2*a*b*cos(C) - assert(num_defined([c,C]) == 1, "Must give exactly one of c= or C=.") - is_undef(c) ? sqrt(a*a + b*b - 2*a*b*cos(C)) : - acos(constrain((a*a + b*b - c*c) / (2*a*b), -1, 1)); - - -// Function: law_of_sines() -// Usage: -// B = law_of_sines(a, A, b); -// b = law_of_sines(a, A, B); -// Topics: Geometry, Triangles -// Description: -// Applies the Law of Sines for an arbitrary triangle. Given two triangle side lengths and the -// angle between them, returns the angle of the corner opposite of the second side. Given a side -// length, the opposing angle, and a second angle, returns the length of the side opposite of the -// second angle. -// Figure(2D): -// stroke([[-50,0], [10,60], [50,0]], closed=true); -// color("black") { -// translate([ 33,35]) text(text="a", size=8, halign="center", valign="center"); -// translate([ 0,-6]) text(text="b", size=8, halign="center", valign="center"); -// translate([-22,35]) text(text="c", size=8, halign="center", valign="center"); -// } -// color("blue") { -// translate([-37, 6]) text(text="A", size=8, halign="center", valign="center"); -// translate([ 9,51]) text(text="B", size=8, halign="center", valign="center"); -// translate([ 38, 6]) text(text="C", size=8, halign="center", valign="center"); -// } -// Arguments: -// a = The length of the first side. -// A = The angle in degrees of the corner opposite of the first side. -// b = The length of the second side. -// B = The angle in degrees of the corner opposite of the second side. -function law_of_sines(a, A, b, B) = - // Triangle Law of Sines: - // a/sin(A) = b/sin(B) = c/sin(C) - assert(num_defined([b,B]) == 1, "Must give exactly one of b= or B=.") - let( r = a/sin(A) ) - is_undef(b) ? r*sin(B) : - asin(constrain(b/r, -1, 1)); - - -// Function: tri_calc() -// Usage: -// triangle = tri_calc(ang,ang2,adj,opp,hyp); -// Topics: Geometry, Triangles -// Description: -// Given a side length and an angle, or two side lengths, calculates the rest of the side lengths -// and angles of a right triangle. Returns [ADJACENT, OPPOSITE, HYPOTENUSE, ANGLE, ANGLE2] where -// ADJACENT is the length of the side adjacent to ANGLE, and OPPOSITE is the length of the side -// opposite of ANGLE and adjacent to ANGLE2. ANGLE and ANGLE2 are measured in degrees. -// This is certainly more verbose and slower than writing your own calculations, but has the nice -// benefit that you can just specify the info you have, and don't have to figure out which trig -// formulas you need to use. -// Figure(2D,NoAxes): -// color("#ccc") { -// stroke(closed=false, width=0.5, [[45,0], [45,5], [50,5]]); -// stroke(closed=false, width=0.5, arc(N=6, r=15, cp=[0,0], start=0, angle=30)); -// stroke(closed=false, width=0.5, arc(N=6, r=14, cp=[50,30], start=212, angle=58)); -// } -// color("black") stroke(closed=true, [[0,0], [50,30], [50,0]]); -// color("#0c0") { -// translate([10.5,2.5]) text(size=3,text="ang",halign="center",valign="center"); -// translate([44.5,22]) text(size=3,text="ang2",halign="center",valign="center"); -// } -// color("blue") { -// translate([25,-3]) text(size=3,text="Adjacent",halign="center",valign="center"); -// translate([53,15]) rotate(-90) text(size=3,text="Opposite",halign="center",valign="center"); -// translate([25,18]) rotate(30) text(size=3,text="Hypotenuse",halign="center",valign="center"); -// } -// Arguments: -// ang = The angle in degrees of the primary corner of the triangle. -// ang2 = The angle in degrees of the other non-right corner of the triangle. -// adj = The length of the side adjacent to the primary corner. -// opp = The length of the side opposite to the primary corner. -// hyp = The length of the hypotenuse. -// Example: -// tri = tri_calc(opp=15,hyp=30); -// echo(adjacent=tri[0], opposite=tri[1], hypotenuse=tri[2], angle=tri[3], angle2=tri[4]); -// Examples: -// adj = tri_calc(ang=30,opp=10)[0]; -// opp = tri_calc(ang=20,hyp=30)[1]; -// hyp = tri_calc(ang2=50,adj=20)[2]; -// ang = tri_calc(adj=20,hyp=30)[3]; -// ang2 = tri_calc(adj=20,hyp=40)[4]; -function tri_calc(ang,ang2,adj,opp,hyp) = - assert(ang==undef || ang2==undef,"At most one angle is allowed.") - assert(num_defined([ang,ang2,adj,opp,hyp])==2, "Exactly two arguments must be given.") - let( - ang = ang!=undef - ? assert(ang>0&&ang<90, "The input angles should be acute angles." ) ang - : ang2!=undef ? (90-ang2) - : adj==undef ? asin(constrain(opp/hyp,-1,1)) - : opp==undef ? acos(constrain(adj/hyp,-1,1)) - : atan2(opp,adj), - ang2 = ang2!=undef - ? assert(ang2>0&&ang2<90, "The input angles should be acute angles." ) ang2 - : (90-ang), - adj = adj!=undef - ? assert(adj>0, "Triangle side lengths should be positive." ) adj - : (opp!=undef? (opp/tan(ang)) : (hyp*cos(ang))), - opp = opp!=undef - ? assert(opp>0, "Triangle side lengths should be positive." ) opp - : (adj!=undef? (adj*tan(ang)) : (hyp*sin(ang))), - hyp = hyp!=undef - ? assert(hyp>0, "Triangle side lengths should be positive." ) - assert(adj=0 && opp>=0, - "Triangle side lengths should be a positive numbers." ) - sqrt(hyp*hyp-opp*opp); - -function opp_hyp_to_adj(opp,hyp) = hyp_opp_to_adj(hyp,opp); - - -// Function: hyp_ang_to_adj() -// Alias: ang_hyp_to_adj() -// Usage: -// adj = hyp_ang_to_adj(hyp,ang); -// Topics: Geometry, Triangles -// Description: -// Given the length of the hypotenuse and the angle of the primary corner of a right triangle, -// returns the length of the adjacent side. -// Arguments: -// hyp = The length of the hypotenuse of the right triangle. -// ang = The angle in degrees of the primary corner of the right triangle. -// Example: -// adj = hyp_ang_to_adj(8,60); // Returns: 4 -function hyp_ang_to_adj(hyp,ang) = - assert(is_finite(hyp) && hyp>=0, "Triangle side length should be a positive number." ) - assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) - hyp*cos(ang); - -function ang_hyp_to_adj(ang,hyp) = hyp_ang_to_adj(hyp, ang); - - -// Function: opp_ang_to_adj() -// Alias: ang_opp_to_adj() -// Usage: -// adj = opp_ang_to_adj(opp,ang); -// Topics: Geometry, Triangles -// Description: -// Given the angle of the primary corner of a right triangle, and the length of the side opposite of it, -// returns the length of the adjacent side. -// Arguments: -// opp = The length of the side of the right triangle that is opposite from the primary angle. -// ang = The angle in degrees of the primary corner of the right triangle. -// Example: -// adj = opp_ang_to_adj(8,30); // Returns: 4 -function opp_ang_to_adj(opp,ang) = - assert(is_finite(opp) && opp>=0, "Triangle side length should be a positive number." ) - assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) - opp/tan(ang); - -function ang_opp_to_adj(ang,opp) = opp_ang_to_adj(opp,ang); - - -// Function: hyp_adj_to_opp() -// Alias: adj_hyp_to_opp() -// Usage: -// opp = hyp_adj_to_opp(hyp,adj); -// Topics: Geometry, Triangles -// Description: -// Given the length of the hypotenuse and the adjacent side, returns the length of the opposite side. -// Arguments: -// hyp = The length of the hypotenuse of the right triangle. -// adj = The length of the side of the right triangle that is adjacent to the primary angle. -// Example: -// opp = hyp_adj_to_opp(5,4); // Returns: 3 -function hyp_adj_to_opp(hyp,adj) = - assert(is_finite(hyp) && hyp>=0 && is_finite(adj) && adj>=0, - "Triangle side lengths should be a positive numbers." ) - sqrt(hyp*hyp-adj*adj); - -function adj_hyp_to_opp(adj,hyp) = hyp_adj_to_opp(hyp,adj); - - -// Function: hyp_ang_to_opp() -// Alias: ang_hyp_to_opp() -// Usage: -// opp = hyp_ang_to_opp(hyp,adj); -// Topics: Geometry, Triangles -// Description: -// Given the length of the hypotenuse of a right triangle, and the angle of the corner, returns the length of the opposite side. -// Arguments: -// hyp = The length of the hypotenuse of the right triangle. -// ang = The angle in degrees of the primary corner of the right triangle. -// Example: -// opp = hyp_ang_to_opp(8,30); // Returns: 4 -function hyp_ang_to_opp(hyp,ang) = - assert(is_finite(hyp)&&hyp>=0, "Triangle side length should be a positive number." ) - assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) - hyp*sin(ang); - -function ang_hyp_to_opp(ang,hyp) = hyp_ang_to_opp(hyp,ang); - - -// Function: adj_ang_to_opp() -// Alias: ang_adj_to_opp() -// Usage: -// opp = adj_ang_to_opp(adj,ang); -// Topics: Geometry, Triangles -// Description: -// Given the length of the adjacent side of a right triangle, and the angle of the corner, returns the length of the opposite side. -// Arguments: -// adj = The length of the side of the right triangle that is adjacent to the primary angle. -// ang = The angle in degrees of the primary corner of the right triangle. -// Example: -// opp = adj_ang_to_opp(8,45); // Returns: 8 -function adj_ang_to_opp(adj,ang) = - assert(is_finite(adj)&&adj>=0, "Triangle side length should be a positive number." ) - assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) - adj*tan(ang); - -function ang_adj_to_opp(ang,adj) = adj_ang_to_opp(adj,ang); - - -// Function: adj_opp_to_hyp() -// Alias: opp_adj_to_hyp() -// Usage: -// hyp = adj_opp_to_hyp(adj,opp); -// Topics: Geometry, Triangles -// Description: -// Given the length of the adjacent and opposite sides of a right triangle, returns the length of thee hypotenuse. -// Arguments: -// adj = The length of the side of the right triangle that is adjacent to the primary angle. -// opp = The length of the side of the right triangle that is opposite from the primary angle. -// Example: -// hyp = adj_opp_to_hyp(3,4); // Returns: 5 -function adj_opp_to_hyp(adj,opp) = - assert(is_finite(opp) && opp>=0 && is_finite(adj) && adj>=0, - "Triangle side lengths should be a positive numbers." ) - norm([opp,adj]); - -function opp_adj_to_hyp(opp,adj) = adj_opp_to_hyp(adj,opp); - - -// Function: adj_ang_to_hyp() -// Alias: ang_adj_to_hyp() -// Usage: -// hyp = adj_ang_to_hyp(adj,ang); -// Topics: Geometry, Triangles -// Description: -// For a right triangle, given the length of the adjacent side, and the corner angle, returns the length of the hypotenuse. -// Arguments: -// adj = The length of the side of the right triangle that is adjacent to the primary angle. -// ang = The angle in degrees of the primary corner of the right triangle. -// Example: -// hyp = adj_ang_to_hyp(4,60); // Returns: 8 -function adj_ang_to_hyp(adj,ang) = - assert(is_finite(adj) && adj>=0, "Triangle side length should be a positive number." ) - assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) - adj/cos(ang); - -function ang_adj_to_hyp(ang,adj) = adj_ang_to_hyp(adj,ang); - - -// Function: opp_ang_to_hyp() -// Alias: ang_opp_to_hyp() -// Usage: -// hyp = opp_ang_to_hyp(opp,ang); -// Topics: Geometry, Triangles -// Description: -// For a right triangle, given the length of the opposite side, and the corner angle, returns the length of the hypotenuse. -// Arguments: -// opp = The length of the side of the right triangle that is opposite from the primary angle. -// ang = The angle in degrees of the primary corner of the right triangle. -// Example: -// hyp = opp_ang_to_hyp(4,30); // Returns: 8 -function opp_ang_to_hyp(opp,ang) = - assert(is_finite(opp) && opp>=0, "Triangle side length should be a positive number." ) - assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) - opp/sin(ang); - -function ang_opp_to_hyp(ang,opp) = opp_ang_to_hyp(opp,ang); - - -// Function: hyp_adj_to_ang() -// Alias: adj_hyp_to_ang() -// Usage: -// ang = hyp_adj_to_ang(hyp,adj); -// Description: -// For a right triangle, given the lengths of the hypotenuse and the adjacent sides, returns the angle of the corner. -// Arguments: -// hyp = The length of the hypotenuse of the right triangle. -// adj = The length of the side of the right triangle that is adjacent to the primary angle. -// Example: -// ang = hyp_adj_to_ang(8,4); // Returns: 60 degrees -function hyp_adj_to_ang(hyp,adj) = - assert(is_finite(hyp) && hyp>0 && is_finite(adj) && adj>=0, - "Triangle side lengths should be positive numbers." ) - acos(adj/hyp); - -function adj_hyp_to_ang(adj,hyp) = hyp_adj_to_ang(hyp,adj); - - -// Function: hyp_opp_to_ang() -// Alias: opp_hyp_to_ang() -// Usage: -// ang = hyp_opp_to_ang(hyp,opp); -// Topics: Geometry, Triangles -// Description: -// For a right triangle, given the lengths of the hypotenuse and the opposite sides, returns the angle of the corner. -// Arguments: -// hyp = The length of the hypotenuse of the right triangle. -// opp = The length of the side of the right triangle that is opposite from the primary angle. -// Example: -// ang = hyp_opp_to_ang(8,4); // Returns: 30 degrees -function hyp_opp_to_ang(hyp,opp) = - assert(is_finite(hyp+opp) && hyp>0 && opp>=0, - "Triangle side lengths should be positive numbers." ) - asin(opp/hyp); - -function opp_hyp_to_ang(opp,hyp) = hyp_opp_to_ang(hyp,opp); - - -// Function: adj_opp_to_ang() -// Alias: opp_adj_to_ang() -// Usage: -// ang = adj_opp_to_ang(adj,opp); -// Topics: Geometry, Triangles -// Description: -// For a right triangle, given the lengths of the adjacent and opposite sides, returns the angle of the corner. -// Arguments: -// adj = The length of the side of the right triangle that is adjacent to the primary angle. -// opp = The length of the side of the right triangle that is opposite from the primary angle. -// Example: -// ang = adj_opp_to_ang(sqrt(3)/2,0.5); // Returns: 30 degrees -function adj_opp_to_ang(adj,opp) = - assert(is_finite(adj+opp) && adj>0 && opp>=0, - "Triangle side lengths should be positive numbers." ) - atan2(opp,adj); - -function opp_adj_to_ang(opp,adj) = adj_opp_to_ang(adj,opp); - - -// Function: triangle_area() -// Usage: -// area = triangle_area(a,b,c); -// Topics: Geometry, Triangles, Area -// Description: -// Returns the area of a triangle formed between three 2D or 3D vertices. -// Result will be negative if the points are 2D and in clockwise order. -// Arguments: -// a = The first vertex of the triangle. -// b = The second vertex of the triangle. -// c = The third vertex of the triangle. -// Examples: -// triangle_area([0,0], [5,10], [10,0]); // Returns -50 -// triangle_area([10,0], [5,10], [0,0]); // Returns 50 -function triangle_area(a,b,c) = - assert( is_path([a,b,c]), "Invalid points or incompatible dimensions." ) - len(a)==3 - ? 0.5*norm(cross(c-a,c-b)) - : 0.5*cross(c-a,c-b); - - - // Section: Planes diff --git a/std.scad b/std.scad index f99e984..39d4544 100644 --- a/std.scad +++ b/std.scad @@ -22,6 +22,7 @@ include include include include +include include include include diff --git a/tests/test_geometry.scad b/tests/test_geometry.scad index ae124fe..c109b47 100644 --- a/tests/test_geometry.scad +++ b/tests/test_geometry.scad @@ -19,19 +19,6 @@ test_line_intersection(); test_line_closest_point(); //test_ray_closest_point(); // should add this type of case test_line_from_points(); -test_tri_calc(); -//test_hyp_opp_to_adj(); -//test_hyp_ang_to_adj(); -//test_opp_ang_to_adj(); -//test_hyp_adj_to_opp(); -//test_hyp_ang_to_opp(); -//test_adj_ang_to_opp(); -//test_adj_opp_to_hyp(); -//test_adj_ang_to_hyp(); -//test_opp_ang_to_hyp(); -//test_hyp_adj_to_ang(); -//test_hyp_opp_to_ang(); -//test_adj_opp_to_ang(); test_plane3pt(); test_plane3pt_indexed(); test_plane_from_normal(); @@ -587,68 +574,6 @@ module test_circle_point_tangents() { *test_circle_point_tangents(); -module test_tri_calc() { - sides = rands(1,100,100,seed_value=8888); - for (p=pair(sides,true)) { - opp = p[0]; - adj = p[1]; - hyp = norm([opp,adj]); - ang = acos(adj/hyp); - ang2 = 90-ang; - expected = [adj, opp, hyp, ang, ang2]; - assert(approx(tri_calc(adj=adj, hyp=hyp), expected)); - assert(approx(tri_calc(opp=opp, hyp=hyp), expected)); - assert(approx(tri_calc(adj=adj, opp=opp), expected)); - assert(approx(tri_calc(adj=adj, ang=ang), expected)); - assert(approx(tri_calc(opp=opp, ang=ang), expected, eps=1e-8)); - assert(approx(tri_calc(hyp=hyp, ang=ang), expected)); - assert(approx(tri_calc(adj=adj, ang2=ang2), expected)); - assert(approx(tri_calc(opp=opp, ang2=ang2), expected, eps=1e-8)); - assert(approx(tri_calc(hyp=hyp, ang2=ang2), expected)); - } -} -*test_tri_calc(); - - -module test_tri_functions() { - sides = rands(1,100,100,seed_value=8181); - for (p = pair(sides,true)) { - adj = p.x; - opp = p.y; - hyp = norm([opp,adj]); - ang = atan2(opp,adj); - assert_approx(hyp_opp_to_adj(hyp,opp), adj); - assert_approx(hyp_ang_to_adj(hyp,ang), adj); - assert_approx(opp_ang_to_adj(opp,ang), adj); - assert_approx(hyp_adj_to_opp(hyp,adj), opp); - assert_approx(hyp_ang_to_opp(hyp,ang), opp); - assert_approx(adj_ang_to_opp(adj,ang), opp); - assert_approx(adj_opp_to_hyp(adj,opp), hyp); - assert_approx(adj_ang_to_hyp(adj,ang), hyp); - assert_approx(opp_ang_to_hyp(opp,ang), hyp); - assert_approx(hyp_adj_to_ang(hyp,adj), ang); - assert_approx(hyp_opp_to_ang(hyp,opp), ang); - assert_approx(adj_opp_to_ang(adj,opp), ang); - } -} -*test_tri_functions(); - - -module test_hyp_opp_to_adj() nil(); // Covered in test_tri_functions() -module test_hyp_ang_to_adj() nil(); // Covered in test_tri_functions() -module test_opp_ang_to_adj() nil(); // Covered in test_tri_functions() -module test_hyp_adj_to_opp() nil(); // Covered in test_tri_functions() -module test_hyp_ang_to_opp() nil(); // Covered in test_tri_functions() -module test_adj_ang_to_opp() nil(); // Covered in test_tri_functions() -module test_adj_opp_to_hyp() nil(); // Covered in test_tri_functions() -module test_adj_ang_to_hyp() nil(); // Covered in test_tri_functions() -module test_opp_ang_to_hyp() nil(); // Covered in test_tri_functions() -module test_hyp_adj_to_ang() nil(); // Covered in test_tri_functions() -module test_hyp_opp_to_ang() nil(); // Covered in test_tri_functions() -module test_adj_opp_to_ang() nil(); // Covered in test_tri_functions() - - - module test_plane3pt() { assert_approx(plane3pt([0,0,20], [0,10,10], [0,0,0]), [1,0,0,0]); assert_approx(plane3pt([2,0,20], [2,10,10], [2,0,0]), [1,0,0,2]); diff --git a/tests/test_trigonometry.scad b/tests/test_trigonometry.scad new file mode 100644 index 0000000..1eeaa53 --- /dev/null +++ b/tests/test_trigonometry.scad @@ -0,0 +1,42 @@ +include <../std.scad> + + +module test_tri_functions() { + sides = rands(1,100,100,seed_value=8181); + for (p = pair(sides,true)) { + adj = p.x; + opp = p.y; + hyp = norm([opp,adj]); + ang = atan2(opp,adj); + + assert_approx(hyp_ang_to_adj(hyp,ang), adj); + assert_approx(opp_ang_to_adj(opp,ang), adj); + assert_approx(hyp_adj_to_opp(hyp,adj), opp); + assert_approx(hyp_ang_to_opp(hyp,ang), opp); + assert_approx(adj_ang_to_opp(adj,ang), opp); + assert_approx(adj_opp_to_hyp(adj,opp), hyp); + assert_approx(adj_ang_to_hyp(adj,ang), hyp); + assert_approx(opp_ang_to_hyp(opp,ang), hyp); + assert_approx(hyp_adj_to_ang(hyp,adj), ang); + assert_approx(hyp_opp_to_ang(hyp,opp), ang); + assert_approx(adj_opp_to_ang(adj,opp), ang); + } +} +*test_tri_functions(); + + +module test_hyp_opp_to_adj() nil(); // Covered in test_tri_functions() +module test_hyp_ang_to_adj() nil(); // Covered in test_tri_functions() +module test_opp_ang_to_adj() nil(); // Covered in test_tri_functions() +module test_hyp_adj_to_opp() nil(); // Covered in test_tri_functions() +module test_hyp_ang_to_opp() nil(); // Covered in test_tri_functions() +module test_adj_ang_to_opp() nil(); // Covered in test_tri_functions() +module test_adj_opp_to_hyp() nil(); // Covered in test_tri_functions() +module test_adj_ang_to_hyp() nil(); // Covered in test_tri_functions() +module test_opp_ang_to_hyp() nil(); // Covered in test_tri_functions() +module test_hyp_adj_to_ang() nil(); // Covered in test_tri_functions() +module test_hyp_opp_to_ang() nil(); // Covered in test_tri_functions() +module test_adj_opp_to_ang() nil(); // Covered in test_tri_functions() + + +// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap diff --git a/trigonometry.scad b/trigonometry.scad new file mode 100644 index 0000000..d4198c7 --- /dev/null +++ b/trigonometry.scad @@ -0,0 +1,390 @@ +////////////////////////////////////////////////////////////////////// +// LibFile: trigonometry.scad +// Trigonometry shortcuts for people who can't be bothered to remember +// all the function relations, or silly acronyms like SOHCAHTOA. +// Includes: +// include +////////////////////////////////////////////////////////////////////// + + + +// Section: 2D General Triangle Functions + + +// Function: law_of_cosines() +// Usage: +// C = law_of_cosines(a, b, c); +// c = law_of_cosines(a, b, C=); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// Applies the Law of Cosines for an arbitrary triangle. Given three side lengths, returns the +// angle in degrees for the corner opposite of the third side. Given two side lengths, and the +// angle between them, returns the length of the third side. +// Figure(2D): +// stroke([[-50,0], [10,60], [50,0]], closed=true); +// color("black") { +// translate([ 33,35]) text(text="a", size=8, halign="center", valign="center"); +// translate([ 0,-6]) text(text="b", size=8, halign="center", valign="center"); +// translate([-22,35]) text(text="c", size=8, halign="center", valign="center"); +// } +// color("blue") { +// translate([-37, 6]) text(text="A", size=8, halign="center", valign="center"); +// translate([ 9,51]) text(text="B", size=8, halign="center", valign="center"); +// translate([ 38, 6]) text(text="C", size=8, halign="center", valign="center"); +// } +// Arguments: +// a = The length of the first side. +// b = The length of the second side. +// c = The length of the third side. +// --- +// C = The angle in degrees of the corner opposite of the third side. +// See Also: law_of_sines() +function law_of_cosines(a, b, c, C) = + // Triangle Law of Cosines: + // c^2 = a^2 + b^2 - 2*a*b*cos(C) + assert(num_defined([c,C]) == 1, "Must give exactly one of c= or C=.") + is_undef(c) ? sqrt(a*a + b*b - 2*a*b*cos(C)) : + acos(constrain((a*a + b*b - c*c) / (2*a*b), -1, 1)); + + +// Function: law_of_sines() +// Usage: +// B = law_of_sines(a, A, b); +// b = law_of_sines(a, A, B=); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// Applies the Law of Sines for an arbitrary triangle. Given two triangle side lengths and the +// angle between them, returns the angle of the corner opposite of the second side. Given a side +// length, the opposing angle, and a second angle, returns the length of the side opposite of the +// second angle. +// Figure(2D): +// stroke([[-50,0], [10,60], [50,0]], closed=true); +// color("black") { +// translate([ 33,35]) text(text="a", size=8, halign="center", valign="center"); +// translate([ 0,-6]) text(text="b", size=8, halign="center", valign="center"); +// translate([-22,35]) text(text="c", size=8, halign="center", valign="center"); +// } +// color("blue") { +// translate([-37, 6]) text(text="A", size=8, halign="center", valign="center"); +// translate([ 9,51]) text(text="B", size=8, halign="center", valign="center"); +// translate([ 38, 6]) text(text="C", size=8, halign="center", valign="center"); +// } +// Arguments: +// a = The length of the first side. +// A = The angle in degrees of the corner opposite of the first side. +// b = The length of the second side. +// --- +// B = The angle in degrees of the corner opposite of the second side. +// See Also: law_of_cosines() +function law_of_sines(a, A, b, B) = + // Triangle Law of Sines: + // a/sin(A) = b/sin(B) = c/sin(C) + assert(num_defined([b,B]) == 1, "Must give exactly one of b= or B=.") + let( r = a/sin(A) ) + is_undef(b) ? r*sin(B) : + asin(constrain(b/r, -1, 1)); + + +// Function: triangle_area() +// Usage: +// area = triangle_area(p1,p2,p3); +// Topics: Geometry, Trigonometry, Triangles, Area +// Description: +// Returns the area of a triangle formed between three 2D or 3D vertices. +// Result will be negative if the points are 2D and in clockwise order. +// Arguments: +// p1 = The first vertex of the triangle. +// p2 = The second vertex of the triangle. +// p3 = The third vertex of the triangle. +// Examples: +// triangle_area([0,0], [5,10], [10,0]); // Returns -50 +// triangle_area([10,0], [5,10], [0,0]); // Returns 50 +function triangle_area(p1,p2,p3) = + assert( is_path([p1,p2,p3]), "Invalid points or incompatible dimensions." ) + len(p1)==3 + ? 0.5*norm(cross(p3-p1,p3-p2)) + : 0.5*cross(p3-p1,p3-p2); + + + +// Section: 2D Right Triangle Functions +// This is a set of functions to make it easier to perform trig calculations on right triangles. +// In general, all these functions are named using these abbreviations: +// - *hyp*: The length of the Hypotenuse. +// - *adj*: The length of the side adjacent to the angle. +// - *opp*: The length of the side opposite to the angle. +// - *ang*: The angle size in degrees. +// If you know two of those, and want to know the value of a third, you will need to call a +// function named like `AAA_BBB_to_CCC()`. For example, if you know the length of the hypotenuse, +// and the length of the side adjacent to the angle, and want to learn the length of the side +// opposite to the angle, you will call `opp = hyp_adj_to_opp(hyp,adj);`. +// Figure(2D): +// color("brown") { +// stroke([[40,0], [40,10], [50,10]]); +// left(50) stroke(arc(r=37,angle=30)); +// } +// color("lightgreen") stroke([[-50,0], [50,60], [50,0]], closed=true); +// color("black") { +// translate([ 62,25]) text(text="opp", size=8, halign="center", valign="center"); +// translate([ 0,-6]) text(text="adj", size=8, halign="center", valign="center"); +// translate([ 0,40]) text(text="hyp", size=8, halign="center", valign="center"); +// translate([-25, 5]) text(text="ang", size=7, halign="center", valign="center"); +// } + + +// Function: hyp_opp_to_adj() +// Alias: opp_hyp_to_adj() +// Usage: +// adj = hyp_opp_to_adj(hyp,opp); +// adj = opp_hyp_to_adj(opp,hyp); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// Given the lengths of the hypotenuse and opposite side of a right triangle, returns the length +// of the adjacent side. +// Arguments: +// hyp = The length of the hypotenuse of the right triangle. +// opp = The length of the side of the right triangle that is opposite from the primary angle. +// Example: +// hyp = hyp_opp_to_adj(5,3); // Returns: 4 +function hyp_opp_to_adj(hyp,opp) = + assert(is_finite(hyp+opp) && hyp>=0 && opp>=0, + "Triangle side lengths should be a positive numbers." ) + sqrt(hyp*hyp-opp*opp); + +function opp_hyp_to_adj(opp,hyp) = hyp_opp_to_adj(hyp,opp); + + +// Function: hyp_ang_to_adj() +// Alias: ang_hyp_to_adj() +// Usage: +// adj = hyp_ang_to_adj(hyp,ang); +// adj = ang_hyp_to_adj(ang,hyp); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// Given the length of the hypotenuse and the angle of the primary corner of a right triangle, +// returns the length of the adjacent side. +// Arguments: +// hyp = The length of the hypotenuse of the right triangle. +// ang = The angle in degrees of the primary corner of the right triangle. +// Example: +// adj = hyp_ang_to_adj(8,60); // Returns: 4 +function hyp_ang_to_adj(hyp,ang) = + assert(is_finite(hyp) && hyp>=0, "Triangle side length should be a positive number." ) + assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) + hyp*cos(ang); + +function ang_hyp_to_adj(ang,hyp) = hyp_ang_to_adj(hyp, ang); + + +// Function: opp_ang_to_adj() +// Alias: ang_opp_to_adj() +// Usage: +// adj = opp_ang_to_adj(opp,ang); +// adj = ang_opp_to_adj(ang,opp); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// Given the angle of the primary corner of a right triangle, and the length of the side opposite of it, +// returns the length of the adjacent side. +// Arguments: +// opp = The length of the side of the right triangle that is opposite from the primary angle. +// ang = The angle in degrees of the primary corner of the right triangle. +// Example: +// adj = opp_ang_to_adj(8,30); // Returns: 4 +function opp_ang_to_adj(opp,ang) = + assert(is_finite(opp) && opp>=0, "Triangle side length should be a positive number." ) + assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) + opp/tan(ang); + +function ang_opp_to_adj(ang,opp) = opp_ang_to_adj(opp,ang); + + +// Function: hyp_adj_to_opp() +// Alias: adj_hyp_to_opp() +// Usage: +// opp = hyp_adj_to_opp(hyp,adj); +// opp = adj_hyp_to_opp(adj,hyp); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// Given the length of the hypotenuse and the adjacent side, returns the length of the opposite side. +// Arguments: +// hyp = The length of the hypotenuse of the right triangle. +// adj = The length of the side of the right triangle that is adjacent to the primary angle. +// Example: +// opp = hyp_adj_to_opp(5,4); // Returns: 3 +function hyp_adj_to_opp(hyp,adj) = + assert(is_finite(hyp) && hyp>=0 && is_finite(adj) && adj>=0, + "Triangle side lengths should be a positive numbers." ) + sqrt(hyp*hyp-adj*adj); + +function adj_hyp_to_opp(adj,hyp) = hyp_adj_to_opp(hyp,adj); + + +// Function: hyp_ang_to_opp() +// Alias: ang_hyp_to_opp() +// Usage: +// opp = hyp_ang_to_opp(hyp,ang); +// opp = ang_hyp_to_opp(ang,hyp); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// Given the length of the hypotenuse of a right triangle, and the angle of the corner, returns the length of the opposite side. +// Arguments: +// hyp = The length of the hypotenuse of the right triangle. +// ang = The angle in degrees of the primary corner of the right triangle. +// Example: +// opp = hyp_ang_to_opp(8,30); // Returns: 4 +function hyp_ang_to_opp(hyp,ang) = + assert(is_finite(hyp)&&hyp>=0, "Triangle side length should be a positive number." ) + assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) + hyp*sin(ang); + +function ang_hyp_to_opp(ang,hyp) = hyp_ang_to_opp(hyp,ang); + + +// Function: adj_ang_to_opp() +// Alias: ang_adj_to_opp() +// Usage: +// opp = adj_ang_to_opp(adj,ang); +// opp = ang_adj_to_opp(ang,adj); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// Given the length of the adjacent side of a right triangle, and the angle of the corner, returns the length of the opposite side. +// Arguments: +// adj = The length of the side of the right triangle that is adjacent to the primary angle. +// ang = The angle in degrees of the primary corner of the right triangle. +// Example: +// opp = adj_ang_to_opp(8,45); // Returns: 8 +function adj_ang_to_opp(adj,ang) = + assert(is_finite(adj)&&adj>=0, "Triangle side length should be a positive number." ) + assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) + adj*tan(ang); + +function ang_adj_to_opp(ang,adj) = adj_ang_to_opp(adj,ang); + + +// Function: adj_opp_to_hyp() +// Alias: opp_adj_to_hyp() +// Usage: +// hyp = adj_opp_to_hyp(adj,opp); +// hyp = opp_adj_to_hyp(opp,adj); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// Given the length of the adjacent and opposite sides of a right triangle, returns the length of thee hypotenuse. +// Arguments: +// adj = The length of the side of the right triangle that is adjacent to the primary angle. +// opp = The length of the side of the right triangle that is opposite from the primary angle. +// Example: +// hyp = adj_opp_to_hyp(3,4); // Returns: 5 +function adj_opp_to_hyp(adj,opp) = + assert(is_finite(opp) && opp>=0 && is_finite(adj) && adj>=0, + "Triangle side lengths should be a positive numbers." ) + norm([opp,adj]); + +function opp_adj_to_hyp(opp,adj) = adj_opp_to_hyp(adj,opp); + + +// Function: adj_ang_to_hyp() +// Alias: ang_adj_to_hyp() +// Usage: +// hyp = adj_ang_to_hyp(adj,ang); +// hyp = ang_adj_to_hyp(ang,adj); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// For a right triangle, given the length of the adjacent side, and the corner angle, returns the length of the hypotenuse. +// Arguments: +// adj = The length of the side of the right triangle that is adjacent to the primary angle. +// ang = The angle in degrees of the primary corner of the right triangle. +// Example: +// hyp = adj_ang_to_hyp(4,60); // Returns: 8 +function adj_ang_to_hyp(adj,ang) = + assert(is_finite(adj) && adj>=0, "Triangle side length should be a positive number." ) + assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) + adj/cos(ang); + +function ang_adj_to_hyp(ang,adj) = adj_ang_to_hyp(adj,ang); + + +// Function: opp_ang_to_hyp() +// Alias: ang_opp_to_hyp() +// Usage: +// hyp = opp_ang_to_hyp(opp,ang); +// hyp = ang_opp_to_hyp(ang,opp); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// For a right triangle, given the length of the opposite side, and the corner angle, returns the length of the hypotenuse. +// Arguments: +// opp = The length of the side of the right triangle that is opposite from the primary angle. +// ang = The angle in degrees of the primary corner of the right triangle. +// Example: +// hyp = opp_ang_to_hyp(4,30); // Returns: 8 +function opp_ang_to_hyp(opp,ang) = + assert(is_finite(opp) && opp>=0, "Triangle side length should be a positive number." ) + assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." ) + opp/sin(ang); + +function ang_opp_to_hyp(ang,opp) = opp_ang_to_hyp(opp,ang); + + +// Function: hyp_adj_to_ang() +// Alias: adj_hyp_to_ang() +// Usage: +// ang = hyp_adj_to_ang(hyp,adj); +// ang = adj_hyp_to_ang(adj,hyp); +// Description: +// For a right triangle, given the lengths of the hypotenuse and the adjacent sides, returns the angle of the corner. +// Arguments: +// hyp = The length of the hypotenuse of the right triangle. +// adj = The length of the side of the right triangle that is adjacent to the primary angle. +// Example: +// ang = hyp_adj_to_ang(8,4); // Returns: 60 degrees +function hyp_adj_to_ang(hyp,adj) = + assert(is_finite(hyp) && hyp>0 && is_finite(adj) && adj>=0, + "Triangle side lengths should be positive numbers." ) + acos(adj/hyp); + +function adj_hyp_to_ang(adj,hyp) = hyp_adj_to_ang(hyp,adj); + + +// Function: hyp_opp_to_ang() +// Alias: opp_hyp_to_ang() +// Usage: +// ang = hyp_opp_to_ang(hyp,opp); +// ang = opp_hyp_to_ang(opp,hyp); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// For a right triangle, given the lengths of the hypotenuse and the opposite sides, returns the angle of the corner. +// Arguments: +// hyp = The length of the hypotenuse of the right triangle. +// opp = The length of the side of the right triangle that is opposite from the primary angle. +// Example: +// ang = hyp_opp_to_ang(8,4); // Returns: 30 degrees +function hyp_opp_to_ang(hyp,opp) = + assert(is_finite(hyp+opp) && hyp>0 && opp>=0, + "Triangle side lengths should be positive numbers." ) + asin(opp/hyp); + +function opp_hyp_to_ang(opp,hyp) = hyp_opp_to_ang(hyp,opp); + + +// Function: adj_opp_to_ang() +// Alias: opp_adj_to_ang() +// Usage: +// ang = adj_opp_to_ang(adj,opp); +// ang = opp_adj_to_ang(opp,adj); +// Topics: Geometry, Trigonometry, Triangles +// Description: +// For a right triangle, given the lengths of the adjacent and opposite sides, returns the angle of the corner. +// Arguments: +// adj = The length of the side of the right triangle that is adjacent to the primary angle. +// opp = The length of the side of the right triangle that is opposite from the primary angle. +// Example: +// ang = adj_opp_to_ang(sqrt(3)/2,0.5); // Returns: 30 degrees +function adj_opp_to_ang(adj,opp) = + assert(is_finite(adj+opp) && adj>0 && opp>=0, + "Triangle side lengths should be positive numbers." ) + atan2(opp,adj); + +function opp_adj_to_ang(opp,adj) = adj_opp_to_ang(adj,opp); + + + +// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap