Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 23 additions & 17 deletions lib/geometry/segment.rb
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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

Expand All @@ -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) &&
Expand Down
17 changes: 17 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
Expand All @@ -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])
Expand Down