Skip to content

Commit

Permalink
Allow intersection_point_with to work with BigDecimal. The method sho…
Browse files Browse the repository at this point in the history
…uld only convert

the numerator to a float if both numerator and denominator are integers.
kaczowkad committed Aug 11, 2016
1 parent 73dc9c9 commit 90caa8c
Showing 2 changed files with 32 additions and 15 deletions.
34 changes: 19 additions & 15 deletions lib/geometry/segment.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
module Geometry
class SegmentsDoNotIntersect < Exception; end
class SegmentsOverlap < Exception; end

class Segment < Struct.new(:point1, :point2)
def self.new_by_arrays(point1_coordinates, point2_coordinates)
self.new(Point.new_by_array(point1_coordinates),
self.new(Point.new_by_array(point1_coordinates),
Point.new_by_array(point2_coordinates))
end

@@ -23,8 +23,8 @@ def topmost_endpoint
def bottommost_endpoint
((point1.y <=> point2.y) == -1) ? point1 : point2
end
def contains_point?(point)

def contains_point?(point)
Geometry.distance(point1, point2) ===
Geometry.distance(point1, point) + Geometry.distance(point, point2)
end
@@ -43,26 +43,30 @@ def intersects_with?(segment)
lies_on_line_intersecting?(segment) &&
segment.lies_on_line_intersecting?(self)
end

def overlaps?(segment)
Segment.have_intersecting_bounds?(self, segment) &&
lies_on_one_line_with?(segment)
end

def intersection_point_with(segment)
raise SegmentsDoNotIntersect unless intersects_with?(segment)
raise SegmentsOverlap if overlaps?(segment)

numerator = (segment.point1.y - point1.y) * (segment.point1.x - segment.point2.x) -
(segment.point1.y - segment.point2.y) * (segment.point1.x - point1.x);
denominator = (point2.y - point1.y) * (segment.point1.x - segment.point2.x) -
denominator = (point2.y - point1.y) * (segment.point1.x - segment.point2.x) -
(segment.point1.y - segment.point2.y) * (point2.x - point1.x);

t = numerator.to_f / denominator;

if numerator.is_a?(Integer) && denominator.is_a?(Integer)
numerator = numerator.to_f
end

t = numerator / denominator;

x = point1.x + t * (point2.x - point1.x)
y = point1.y + t * (point2.y - point1.y)
y = point1.y + t * (point2.y - point1.y)

Point.new(x, y)
end

@@ -91,13 +95,13 @@ def distance_to(point)
return Geometry.distance(q, p)
end

def length
def length
Geometry.distance(point1, point2)
end

def to_vector
Vector.new(point2.x - point1.x, point2.y - point1.y)
end
end

protected

@@ -107,7 +111,7 @@ def self.have_intersecting_bounds?(segment1, segment2)
segment1.leftmost_endpoint.x == segment2.rightmost_endpoint.x) &&
(segment2.leftmost_endpoint.x < segment1.rightmost_endpoint.x ||
segment2.leftmost_endpoint.x == segment1.rightmost_endpoint.x)

intersects_on_y_axis =
(segment1.bottommost_endpoint.y < segment2.topmost_endpoint.y ||
segment1.bottommost_endpoint.y == segment2.topmost_endpoint.y) &&
13 changes: 13 additions & 0 deletions test/segment/intersection_point_with_test.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'minitest/autorun'
require 'geometry'
require 'bigdecimal'

class IntersectionPointWithTest < Minitest::Test
include Geometry
@@ -18,6 +19,18 @@ def test_segments_intersect_at_the_endpoint
assert_equal Point.new(2, 2), segment1.intersection_point_with(segment2)
end

def test_big_decimal_segments_intersect_at_the_endpoint
segment1 = Segment.new_by_arrays([BigDecimal.new('-109.775390625'), BigDecimal.new('42.734102391081')],
[BigDecimal.new('-91.23046875'), BigDecimal.new('42.734102391081')])

segment2 = Segment.new_by_arrays([BigDecimal.new('-91.23046875'), BigDecimal.new('42.734102391081')],
[BigDecimal.new('-91.23046875'), BigDecimal.new('34.147272023649')])


assert_equal Point.new(BigDecimal.new('-91.23046875'), BigDecimal.new('42.734102391081')),
segment1.intersection_point_with(segment2)
end

def test_segments_do_not_intersect
segment1 = Segment.new_by_arrays([0, 0], [0, 2])
segment2 = Segment.new_by_arrays([1, 1], [2, 1])

0 comments on commit 90caa8c

Please sign in to comment.