Triangle Area (#160)

Here’s my own solution. It’s a Monte Carlo solution. It’s accuracy
isn’t that great; I had to jack up the tolerance and the samples a
good amount, and still couldn’t pass the tests regularly.

I know when I’ve done MC in the past (back in college), my random
number generator was biased and would throw things off. I don’t think
there is bias here, but I’m not certain.

Anyway, I’ve always liked the idea of MC for certain situations.
Certainly, I had an exact triangle area function done in 5 minutes
using the determinant (which helped me create the unit tests). But I
wanted my own submission to be a little different.

And hooray for Barycentric coordinates! Makes the point inside
triangle test real simple.

require “triangle”
require “mathn”

SAMPLE = 50000

def rand_f(lo, hi)
rand * (hi - lo) + lo
end

class Bounds
def initialize(l, t, r, b)
@l, @t, @r, @b = l, t, r, b
end

def Bounds.enclosing(*pts)
horz, vert = pts.map { |v| v[0] }, pts.map{ |v| v[1] }
Bounds.new(horz.min, vert.min, horz.max, vert.max)
end

def area
(@r - @l) * (@b - @t)
end

def rand_pt
Vector[rand_f(@l, @r), rand_f(@t, @b)]
end

def inspect
“Bounds(#{@l}, #{@t}, #{@r}, #{@b})”
end
end

class Triangle
def area
bnd = Bounds.enclosing(@a, @b, @c)
return 0 if bnd.area.zero?

  hits = 0
  SAMPLE.times do
     hits += 1 if self.contains(bnd.rand_pt)
  end

  bnd.area * hits / SAMPLE.to_f

end

def contains(pt)
x0, x1, x2, x3 = pt[0], @a[0], @b[0], @c[0]
y0, y1, y2, y3 = pt[1], @a[1], @b[1], @c[1]

  # Compute barycentric coordinates b1, b2, b3
  b0 =  (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1)
  return nil if b0.zero?

  b1 = ((x2 - x0) * (y3 - y0) - (x3 - x0) * (y2 - y0)) / b0
  b2 = ((x3 - x0) * (y1 - y0) - (x1 - x0) * (y3 - y0)) / b0
  b3 = ((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)) / b0

  # Point is contained if none of b1, b2, b3 are negative
  b1 >= 0 and b2 >= 0 and b3 >= 0

end
end

On Sat, Apr 19, 2008 at 10:39 AM, Matthew M. [email protected]
wrote:

Quiz #160
Triangle Area

Here’s my solution. Nothing fancy. Good old Heron’s formula. I had
actually started with the cross product of the vectors describing two
sides of a triangle, but since Vector doesn’t have an outer_product
method and implementing that for N dimentions got kind of ugly, I
switched to the alternative that’s also dimension-independent, which is
still four lines of code :slight_smile:

Marcelo