diff --git a/lib/geometry/line.rb b/lib/geometry/line.rb index 94d96b7..b5e7a69 100644 --- a/lib/geometry/line.rb +++ b/lib/geometry/line.rb @@ -67,6 +67,55 @@ def self.[](*args) end end + # @return [Array] intersection points + def intersection(object) + result = [] + if object.kind_of?(Line) then + unless object.vertical? && self.vertical? then + if object.vertical? || self.vertical? then + if object.vertical? then + m = slope + c = intercept + x = object.intercept(:x) + else + m = object.slope + c = object.intercept + x = intercept(:x) + end + y = m * x + c + result = [Point[x,y]] + else + m1 = slope + m2 = object.slope + c1 = intercept + c2 = object.intercept + if m1 != m2 then + x = (c2 - c1) / (m1 - m2) + y = m1 * x + c1 + result = [Point[x,y]] + end + end + end + elsif object.kind_of?(Polyline) then + points = object.edges.map do |edge| + point = intersection(Line[edge.first,edge.last]).first + if point != nil then + x1 , x2 = [edge.first.x , edge.last.x ].sort + y1 , y2 = [edge.first.y , edge.last.y ].sort + unless (x1 .. x2).include?(point.x) && (y1 .. y2).include?(point.y) then + point = nil + end + end + next point + end + result = points.compact.uniq + else + raise ArgumentError + end + return result + end + + # @overload new(from, to) # @option options [Point] :from A starting {Point} # @option options [Point] :to An end {Point} @@ -280,4 +329,3 @@ def intercept(axis=:y) # @endgroup end end - diff --git a/test/geometry/line.rb b/test/geometry/line.rb index 3fb314e..281c77d 100644 --- a/test/geometry/line.rb +++ b/test/geometry/line.rb @@ -105,6 +105,43 @@ line = Geometry::Line[[0,0], [10,10]] assert_equal('Line(Point[0, 0], Point[10, 10])', line.to_s) end + it "line intersection" do + line1 = Geometry::Line[[1,1],[3,3]] + line2 = Geometry::Line[[1,3],[3,1]] + assert_equal [Geometry::Point[2,2]], line1.intersection(line2) + assert_equal [Geometry::Point[2,2]], line2.intersection(line1) + end + it "verctical line intersection" do + line1 = Geometry::Line[[1,1],[1,2]] + line2 = Geometry::Line[[0,0],[2,2]] + assert_equal [Geometry::Point[1,1]], line2.intersection(line1) + assert_equal [Geometry::Point[1,1]], line1.intersection(line2) + end + it "paralells lines shouldn't intercept" do + line1 = Geometry::Line[[2,0],[2,0]] + line2 = Geometry::Line[[1,0],[1,0]] + assert_equal [], line2.intersection(line1) + + line1 = Geometry::Line[[0,2],[0,2]] + line2 = Geometry::Line[[0,1],[0,1]] + assert_equal [], line2.intersection(line1) + + line1 = Geometry::Line[[0,0],[1,1]] + line2 = Geometry::Line[[2,3],[3,4]] + assert_equal [], line2.intersection(line1) + end + it "polygon intersection" do + b = proc{ |p1,p2| p1.to_a <=> p2.to_a } + polygon = Geometry::Polygon.new([1,1] ,[1,3], [3,3], [3,1]) + line = Geometry::Line[[0,2],[4,2]] + assert_equal [Geometry::Point[1, 2],Geometry::Point[3, 2]].sort(&b) , line.intersection(polygon).sort(&b) + line = Geometry::Line[[2,0],[2,4]] + assert_equal [Geometry::Point[2, 3],Geometry::Point[2, 1]].sort(&b), line.intersection(polygon).sort(&b) + line = Geometry::Line[[3,3],[4,4]] + assert_equal [Geometry::Point[1, 1],Geometry::Point[3, 3]].sort(&b), line.intersection(polygon).sort(&b) + line = Geometry::Line[[0,6],[10,15]] + assert_equal [], line.intersection(polygon) + end end describe Geometry::PointSlopeLine do