Distance from a point to a line segment in Ruby
New here? Learn about Bountify and follow @bountify to get notified of new bounties! x

Hi,

I want the Ruby code for calculating the distance from a point to a line segment (calculate(point, line_segment))

A point should be represented as a hash with x and y keys. X and Y components are integers.

A line segment should be represented by a hash containing its end-points, keyed with a and b.

This is similar to this task but with line segments.

Thanks!

awarded to alex
Tags
ruby

Crowdsource coding tasks.

1 Solution

Winning solution

This function should work for you

def calculate(point, line_segment)
    segment_aX = line_segment[:a][:x]
    segment_aY = line_segment[:a][:y]
    segment_bX = line_segment[:b][:x]
    segment_bY = line_segment[:b][:y]

    length2 = (segment_aX - segment_bX)**2 + (segment_aY - segment_bY)**2

    if length2 == 0
        return Math.sqrt(distTo(point, line_segment[:a]))
    else
        t = ((point[:x] - segment_aX) * (segment_bX - segment_aX) + (point[:y] - segment_aY) * (segment_bY - segment_aY)) / length2
        if t < 0
            return Math.sqrt(distTo(point, line_segment[:a]))
        elsif t > 1
            return Math.sqrt(distTo(point, line_segment[:b]))
        else
            tempPoint = {
                :x => (segment_aX + t * (segment_bX - segment_aX)).to_i,
                :y => segment_aY + t * (segment_bY - segment_aY).to_i
            }
            squareAns = distTo(point, tempPoint)
            return Math.sqrt(squareAns)
        end
    end
end

def distTo(point1, point2)
    return ((point1[:x] - point2[:x])**2 + (point1[:y] - point2[:y])**2)
end

with usage as follows:

#!/usr/bin/ruby

point = {
    :x => 0,
    :y => 0
}

segment = {
    :a => {
        :x => 1,
        :y => 2
    },
    :b => {
        :x => 2,
        :y => 2
    }
}

def calculate(point, line_segment)
    segment_aX = line_segment[:a][:x]
    segment_aY = line_segment[:a][:y]
    segment_bX = line_segment[:b][:x]
    segment_bY = line_segment[:b][:y]

    length2 = (segment_aX - segment_bX)**2 + (segment_aY - segment_bY)**2

    if length2 == 0
        return Math.sqrt(distTo(point, line_segment[:a]))
    else
        t = ((point[:x] - segment_aX) * (segment_bX - segment_aX) + (point[:y] - segment_aY) * (segment_bY - segment_aY)) / length2
        if t < 0
            return Math.sqrt(distTo(point, line_segment[:a]))
        elsif t > 1
            return Math.sqrt(distTo(point, line_segment[:b]))
        else
            tempPoint = {
                :x => (segment_aX + t * (segment_bX - segment_aX)).to_i,
                :y => segment_aY + t * (segment_bY - segment_aY).to_i
            }
            squareAns = distTo(point, tempPoint)
            return Math.sqrt(squareAns)
        end
    end
end

def distTo(point1, point2)
    return ((point1[:x] - point2[:x])**2 + (point1[:y] - point2[:y])**2)
end

print calculate(point,segment)
print "\n"

~ Alex