diff --git a/geometry.scad b/geometry.scad
index d66bfb8..059b516 100644
--- a/geometry.scad
+++ b/geometry.scad
@@ -249,12 +249,13 @@ function segment_closest_point(seg,pt) =
 //   labels = [[pts[0], "pt1"], [pts[1],"pt2"], [pts[2],"pt3"], [circ[0], "CP"], [circ[0]+[cos(315),sin(315)]*rad*0.7, "r"]];
 //   for(l=labels) translate(l[0]+[0,2]) color("black") text(text=l[1], size=2.5, halign="center");
 function find_circle_2tangents(pt1, pt2, pt3, r=undef, d=undef) =
+	let(r = get_radius(r=r, d=d, dflt=undef))
+	assert(r!=undef, "Must specify either r or d.")
+	(is_undef(pt2) && is_undef(pt3) && is_list(pt1))? find_circle_2tangents(pt1[0], pt1[1], pt1[2], r=r) :
 	let(
-		r = get_radius(r=r, d=d, dflt=undef),
 		v1 = normalize(pt1 - pt2),
 		v2 = normalize(pt3 - pt2)
 	) approx(norm(v1+v2))? undef :
-	assert(r!=undef, "Must specify either r or d.")
 	let(
 		a = vector_angle(v1,v2),
 		n = vector_axis(v1,v2),
@@ -285,6 +286,7 @@ function find_circle_2tangents(pt1, pt2, pt3, r=undef, d=undef) =
 //   translate(circ[0]) color("red") circle(d=3, $fn=12);
 //   place_copies(pts) color("blue") circle(d=3, $fn=12);
 function find_circle_3points(pt1, pt2, pt3) =
+	(is_undef(pt2) && is_undef(pt3) && is_list(pt1))? find_circle_3points(pt1[0], pt1[1], pt1[2]) :
 	collinear(pt1,pt2,pt3)? [undef,undef,undef] :
 	let(
 		v1 = pt1-pt2,
@@ -299,7 +301,7 @@ function find_circle_3points(pt1, pt2, pt3) =
 			res = find_circle_3points(a, b, c)
 		) res[0]==undef? [undef,undef,undef] : let(
 			cp = lift_plane(res[0], pt1, pt2, pt3),
-			r = norm(p2-cp)
+			r = norm(pt2-cp)
 		) [cp, r, n2]
 	) : let(
 		mp1 = pt2 + v1/2,
@@ -394,7 +396,7 @@ function find_circle_tangents(r, d, cp, pt) =
 //   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(num_defined([ang,ang2])<2,"You cannot specify both ang and ang2.")
+	assert(ang==undef || ang2==undef,"You cannot specify both ang and ang2.")
 	assert(num_defined([ang,ang2,adj,opp,hyp])==2, "You must specify exactly two arguments.")
 	let(
 		ang = ang!=undef? assert(ang>0&&ang<90) ang :
@@ -413,6 +415,200 @@ function tri_calc(ang,ang2,adj,opp,hyp) =
 	[adj, opp, hyp, ang, ang2];
 
 
+// Function: hyp_opp_to_adj()
+// Usage:
+//   adj = hyp_opp_to_adj(hyp,opp);
+// 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_num(hyp)&&hyp>=0)
+	assert(is_num(opp)&&opp>=0)
+	sqrt(hyp*hyp-opp*opp);
+
+
+// Function: hyp_ang_to_adj()
+// Usage:
+//   adj = hyp_ang_to_adj(hyp,ang);
+// 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_num(hyp)&&hyp>=0)
+	assert(is_num(ang)&&ang>0&&ang<90)
+	hyp*cos(ang);
+
+
+// Function: opp_ang_to_adj()
+// Usage:
+//   adj = opp_ang_to_adj(opp,ang);
+// 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_num(opp)&&opp>=0)
+	assert(is_num(ang)&&ang>0&&ang<90)
+	opp/tan(ang);
+
+
+// Function: hyp_adj_to_opp()
+// Usage:
+//   opp = hyp_adj_to_opp(hyp,adj);
+// 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_num(hyp)&&hyp>=0)
+	assert(is_num(adj)&&adj>=0)
+	sqrt(hyp*hyp-adj*adj);
+
+
+// Function: hyp_ang_to_opp()
+// Usage:
+//   opp = hyp_ang_to_opp(hyp,adj);
+// 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_num(hyp)&&hyp>=0)
+	assert(is_num(ang)&&ang>0&&ang<90)
+	hyp*sin(ang);
+
+
+// Function: adj_ang_to_opp()
+// Usage:
+//   opp = adj_ang_to_opp(adj,ang);
+// 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_num(adj)&&adj>=0)
+	assert(is_num(ang)&&ang>0&&ang<90)
+	adj*tan(ang);
+
+
+// Function: adj_opp_to_hyp()
+// Usage:
+//   hyp = adj_opp_to_hyp(adj,opp);
+// 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_num(adj)&&adj>=0)
+	assert(is_num(opp)&&opp>=0)
+	norm([opp,adj]);
+
+
+// Function: adj_ang_to_hyp()
+// Usage:
+//   hyp = adj_ang_to_hyp(adj,ang);
+// 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_num(adj)&&adj>=0)
+	assert(is_num(ang)&&ang>=0&&ang<90)
+	adj/cos(ang);
+
+
+// Function: opp_ang_to_hyp()
+// Usage:
+//   hyp = opp_ang_to_hyp(opp,ang);
+// 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_num(opp)&&opp>=0)
+	assert(is_num(ang)&&ang>0&&ang<=90)
+	opp/sin(ang);
+
+
+// Function: hyp_adj_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_num(hyp)&&hyp>0)
+	assert(is_num(adj)&&adj>=0)
+	acos(adj/hyp);
+
+
+// Function: hyp_opp_to_ang()
+// Usage:
+//   ang = hyp_opp_to_ang(hyp,opp);
+// 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_num(hyp)&&hyp>0)
+	assert(is_num(opp)&&opp>=0)
+	asin(opp/hyp);
+
+
+// Function: adj_opp_to_ang()
+// Usage:
+//   ang = adj_opp_to_ang(adj,opp);
+// 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_num(adj)&&adj>=0)
+	assert(is_num(opp)&&opp>=0)
+	atan2(opp,adj);
+
 
 // Function: triangle_area()
 // Usage:
@@ -486,8 +682,10 @@ function plane_from_pointslist(points) =
 		indices = find_noncollinear_points(points),
 		p1 = points[indices[0]],
 		p2 = points[indices[1]],
-		p3 = points[indices[2]]
-	) plane3pt(p1,p2,p3);
+		p3 = points[indices[2]],
+		plane = plane3pt(p1,p2,p3),
+		out = ((plane.x+plane.y+plane.z)<0)? plane3pt(p1,p3,p2) : plane
+	) out;
 
 
 // Function: plane_normal()
@@ -512,7 +710,7 @@ function plane_normal(plane) = [for (i=[0:2]) plane[i]];
 //   plane = The [A,B,C,D] values for the equation of the plane.
 //   point = The point to test.
 function distance_from_plane(plane, point) =
-	[plane.x, plane.y, plane.z] * point - plane[3];
+	[plane.x, plane.y, plane.z] * point3d(point) - plane[3];
 
 
 // Function: coplanar()