[postgis-devel] ForceRHR doesn't?

Michael Fuhr mike at fuhr.org
Sat Mar 11 19:50:16 PST 2006


On Sat, Mar 11, 2006 at 02:29:15AM -0700, Michael Fuhr wrote:
> ForceRHR does a reverse instead of forcing a particular point order.
> Am I misunderstanding something or is that broken?

To clarify: ForceRHR() does an unconditional reverse instead of
reversing only when necessary.  Am I correct in understanding that
ForceRHR() should return points in counter-clockwise order?

I changed lwgeom_forceRHR() to call lwpoly_forceRHR() instead of
lwpoly_reverse() and it appears to work the way I expect:

SELECT AsText(ForceRHR('POLYGON((0 0,10 0,5 5,0 0))'));
           astext            
-----------------------------
 POLYGON((0 0,10 0,5 5,0 0))
(1 row)

SELECT AsText(ForceRHR('POLYGON((0 0,5 5,10 0,0 0))'));
           astext            
-----------------------------
 POLYGON((0 0,10 0,5 5,0 0))
(1 row)

However, the "fixed" code returns interior rings in clockwise order.
Is that correct?

SELECT AsText(ForceRHR('POLYGON((0 0,10 0,5 5,0 0),(1 1,9 1,4 4,1 1))'));
                    astext                     
-----------------------------------------------
 POLYGON((0 0,10 0,5 5,0 0),(1 1,4 4,9 1,1 1))
(1 row)

This is happening because lwpoly_forceRHR() uses opposite tests for
the exterior and interior rings:

    if ( ptarray_isccw(poly->rings[0]) )
    {
            ptarray_reverse(poly->rings[0]);
    }

    for (i=1; i<poly->nrings; i++)
    {
            if ( ! ptarray_isccw(poly->rings[i]) )
            {
                    ptarray_reverse(poly->rings[i]);
            }
    }

Since this code does do the right thing (as I understand it) for
the exterior ring and the wrong thing for the interior rings,
ptarray_isccw() must be returning true when the points are clockwise
and false when they're counter-clockwise, which is contrary to what
its name suggests (I'm assuming "isccw" means "is counter-clockwise").
Shouldn't ptarray_isccw() return true when the points are counter-
clockwise?  And if so then shouldn't the exterior ring's test be
"if ( ! ptarray_isccw(poly->rings[0]) )"?

I've attached a patch that makes ForceRHR() work the way I was
expecting: return the points of the exterior and interior rings in
counter-clockwise order.  If I've misunderstood what ForceRHR() is
supposed to do then somebody please correct me.  Thanks.

-- 
Michael Fuhr
-------------- next part --------------
Index: lwgeom/lwgeom.c
===================================================================
RCS file: /home/cvs/postgis/postgis/lwgeom/lwgeom.c,v
retrieving revision 1.31
diff -c -r1.31 lwgeom.c
*** lwgeom/lwgeom.c	29 Jan 2006 13:54:38 -0000	1.31
--- lwgeom/lwgeom.c	12 Mar 2006 03:39:03 -0000
***************
*** 133,139 ****
  	switch (TYPE_GETTYPE(lwgeom->type))
  	{
  		case POLYGONTYPE:
! 			lwpoly_reverse((LWPOLY *)lwgeom);
  			return;
  
  		case MULTIPOLYGONTYPE:
--- 133,139 ----
  	switch (TYPE_GETTYPE(lwgeom->type))
  	{
  		case POLYGONTYPE:
! 			lwpoly_forceRHR((LWPOLY *)lwgeom);
  			return;
  
  		case MULTIPOLYGONTYPE:
Index: lwgeom/lwgeom_api.c
===================================================================
RCS file: /home/cvs/postgis/postgis/lwgeom/lwgeom_api.c,v
retrieving revision 1.85
diff -c -r1.85 lwgeom_api.c
*** lwgeom/lwgeom_api.c	19 Jan 2006 18:16:17 -0000	1.85
--- lwgeom/lwgeom_api.c	12 Mar 2006 03:39:03 -0000
***************
*** 1869,1876 ****
  		getPoint2d_p(pa, i+1, &p2);
  		area += (p1.x * p2.y) - (p1.y * p2.x);
  	}
! 	if ( area > 0 ) return 0;
! 	else return 1;
  }
  
  /*
--- 1869,1876 ----
  		getPoint2d_p(pa, i+1, &p2);
  		area += (p1.x * p2.y) - (p1.y * p2.x);
  	}
! 	if ( area > 0 ) return 1;
! 	else return 0;
  }
  
  /*
Index: lwgeom/lwpoly.c
===================================================================
RCS file: /home/cvs/postgis/postgis/lwgeom/lwpoly.c,v
retrieving revision 1.21
diff -c -r1.21 lwpoly.c
*** lwgeom/lwpoly.c	30 Dec 2005 17:40:37 -0000	1.21
--- lwgeom/lwpoly.c	12 Mar 2006 03:39:03 -0000
***************
*** 463,469 ****
  {
  	int i;
  
! 	if ( ptarray_isccw(poly->rings[0]) )
  	{
  		ptarray_reverse(poly->rings[0]);
  	}
--- 463,469 ----
  {
  	int i;
  
! 	if ( ! ptarray_isccw(poly->rings[0]) )
  	{
  		ptarray_reverse(poly->rings[0]);
  	}


More information about the postgis-devel mailing list