From: Todd Benson Date: 2008-04-22T10:20:15+09:00 Subject: Re: [QUIZ] Triangle Area (#160) On Mon, Apr 21, 2008 at 6:50 PM, Adam Shelly wrote: > On 4/21/08, Todd Benson wrote: > > > I suppose another way to approach it could be to use a matrix > > transformation to get your 'base' (turn the triangle, or the > > coordinate system; however you prefer to see it) and use a simple > > 1/2(b*h). > > 1/2(b*h) wa the first thing I thought of when I read the quiz title. > Here's my implementation: > > class Triangle > def area > pts = [@a, @b, @c] > #filter out degenerate triangles > return 0 if pts.uniq! > > #move one point to the origin > offset = pts[0]*-1.0 > pts.map!{|v|v+=offset} > > #find the angle of one leg > angle=Math::atan(pts[1][1]/pts[1][0]) > > #rotate that leg so it lies along X axis > rotmat = Matrix.rows( [[Math::cos(angle),Math::sin(angle)], > [-Math::sin(angle),Math::cos(angle)]]) > pts.map!{|v|rotmat*v} > > #use basic geometry > base = pts[1][0].abs > height = pts[2][1].abs > area=base*height/ 2.0 > end > end > > > -Adam That is awesome! It's almost exactly what I had in mind. The cool thing about it is you can expand it, if need be, to three dimensions with only a couple changes. Only a couple of small things. You want to return 0 if Vector objects happen to be uniq!? Or, are you using my nested array model? For example... [Vector[1, 1], Vector[1, 1], Vector[1, 1]].uniq! => nil That's using 1.8.6 on Windoze. Also, "bad" triangles can have legs that are almost collinear, which, depending on your use case, you might have to check for. I didn't. Sigh :/ But, it turns out I didn't have to. It correctly returns an area of 0.0. For performance reasons -- which I don't really often care about when I use Ruby -- you could set up Math::sin and Math::cos before the creation of the Matrix, since that Matrix creation is calling both twice. Good stuff! Todd