diff --git a/lib/geometry/segment.rb b/lib/geometry/segment.rb index b593d86..2157392 100644 --- a/lib/geometry/segment.rb +++ b/lib/geometry/segment.rb @@ -1,11 +1,11 @@ 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), - Point.new_by_array(point2_coordinates)) + new(Point.new_by_array(point1_coordinates), + Point.new_by_array(point2_coordinates)) end def leftmost_endpoint @@ -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,32 @@ 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) - - (segment.point1.y - segment.point2.y) * (point2.x - point1.x); + denominator = (point2.y - point1.y) * + (segment.point1.x - segment.point2.x) - + (segment.point1.y - segment.point2.y) * + (point2.x - point1.x) + + if numerator.is_a?(Integer) && denominator.is_a?(Integer) + numerator = numerator.to_f + end + + t = numerator / denominator - t = numerator.to_f / 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 +97,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 +113,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) && diff --git a/test/segment/intersection_point_with_test.rb b/test/segment/intersection_point_with_test.rb index 6c62864..cb8d9bb 100644 --- a/test/segment/intersection_point_with_test.rb +++ b/test/segment/intersection_point_with_test.rb @@ -1,5 +1,6 @@ require 'minitest/autorun' require 'geometry' +require "bigdecimal" class IntersectionPointWithTest < Minitest::Test include Geometry @@ -18,6 +19,22 @@ 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])