0

I try to rewrite this piece of Javascript code, coming from http://jsfromhell.com/math/is-point-in-poly, in coffeescript. It detects if a point is in a polygon, and works perfectly fine, but I am not sure what an elegant coffeescript translation would be?

function isPointInPoly(poly, pt){
  for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
    ((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y))
    && (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x)
    && (c = !c);
return c;
}
3
  • 4
    Have you tried to get an elegant JavaScript version at first? Commented Sep 30, 2013 at 15:10
  • js2coffee.org Commented Sep 30, 2013 at 15:11
  • Thank you for js2coffee.org, that's a good one. Since my question is awarded -1 I probably have not asked clearly enough what my main issue is: what would be the appropriate way to rewrite a for-loop with assignments inside the declaration? The while loop suggested by js2coffee is the way to go? Commented Sep 30, 2013 at 15:22

2 Answers 2

4

Just as a point of comparison (pun intended), here's a version of this algorithm I wrote several years ago as part of PolyGonzo (a fast polygon drawing library I used in Google's election maps). This is adapted from the original, which handled multipolygons as commonly used in geographic work instead of just single polygons.

I wrote this code for speed - it should be quite a bit faster than the code in the question for old browsers, and somewhat faster in new browsers. (I haven't benchmarked it in a while, but I suspect the difference is less now that browsers have gotten better at optimizing JavaScript.)

For example, it avoids all of the repeated array and property dereferencing used in the jsfromhell example. I think it's a bit easier to read too. Of course the algorithm itself is still a bit complicated!

function pointInPoly( poly, point ) {
    var inside = false,
        x = point.x, y = point.y,
        n = poly.length,
        vertex = poly[ n - 1 ],
        x1 = vertex.x, y1 = vertex.y;

    for( var i = 0;  i < n;  ++i ) {
        vertex = poly[i];
        var x2 = vertex.x, y2 = vertex.y;

        if( ( y1 < y ) != ( y2 < y ) )
            if( x1 + ( y - y1 ) / ( y2 - y1 ) * ( x2 - x1 ) < x )
                inside = ! inside;

        x1 = x2, y1 = y2;
    }

    return inside;
}

I don't really like the translation that js2coffee.org produces for that code. In particular, the nested if statements in the loop turn into a long one-liner:

inside = not inside  if x1 + (y - y1) / (y2 - y1) * (x2 - x1) < x  unless (y1 < y) is (y2 < y)

But it was easy to use that as a starting point and turn it into a nicer CoffeeScript version:

pointInPoly = ( poly, point ) ->
    inside = false
    x = point.x
    y = point.y

    vertex = poly[ poly.length - 1 ]
    x1 = vertex.x
    y1 = vertex.y

    for vertex in poly
        x2 = vertex.x
        y2 = vertex.y
        if ( y1 < y ) != ( y2 < y )
            if x1 + ( y - y1 ) / ( y2 - y1 ) * ( x2 - x1 ) < x
                inside = not inside
        x1 = x2
        y1 = y2

    inside

This is a few more lines of code than the other version, but again it's optimized more for speed than brevity.

Sign up to request clarification or add additional context in comments.

1 Comment

It is also clearer. Depending on shortcut || and && makes the code quite opaque.
1

I'd go with

isPointInPoly = (poly, pt) ->
  c = false
  j = poly.length - 1
  for b, i in poly
    a = poly[j]
    if ((a.y <= pt.y && pt.y < b.y) || (b.y <= pt.y && pt.y < a.y)) && (pt.x < (b.x - a.x) * (pt.y - a.y) / (b.y - a.y) + a.x)
      c = not c
    j = i
  c

(demo compilation)

1 Comment

@muistooshort: But when there is no other loop in that function… You're right, there's no guarantee and one should not use them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.