Commit b7db0ef8 authored by charras's avatar charras
Browse files

updating polygon lib code. A bug removed.

parent 7c5feb61
Loading
Loading
Loading
Loading
+2 −14
Original line number Diff line number Diff line
@@ -169,16 +169,8 @@ int BOARD::TestAreaPolygon( ZONE_CONTAINER* CurrArea )
                            int y2i    = p->GetY( is2 );
                            int x2f    = p->GetX( is2_next );
                            int y2f    = p->GetY( is2_next );
                            int ret    = FindSegmentIntersections( x1i,
                                                                   y1i,
                                                                   x1f,
                                                                   y1f,
                                                                   style,
                                                                   x2i,
                                                                   y2i,
                                                                   x2f,
                                                                   y2f,
                                                                   style2 );
                            int ret    = FindSegmentIntersections( x1i, y1i, x1f, y1f, style,
                                                                   x2i, y2i, x2f, y2f, style2 );
                            if( ret )
                            {
                                // intersection between non-adjacent sides
@@ -246,8 +238,6 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
            str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" );
            str += wxT( "Manual correction is recommended." );
            wxMessageBox( str );

//          bDontShowSelfIntersectionArcsWarning = dlg.bDontShowBoxState;
        }
        return -1;  // arcs intersect with other sides, error
    }
@@ -427,8 +417,6 @@ int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtilit
                                        curr_area->m_Netname.GetData() );
                                    str += wxT( "Therefore, these areas can't be combined." );
                                    wxMessageBox( str );

//                                    bDontShowIntersectionArcsWarning = dlg.bDontShowBoxState;
                                }
                            }
                        }
+83 −100
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ CPolyLine::~CPolyLine()
        delete m_Kbool_Poly_Engine;
}


/** Function NormalizeWithKbool
 * Use the Kbool Library to clip contours: if outlines are crossing, the self-crossing polygon
 * is converted to non self-crossing polygon by adding extra points at the crossing locations
@@ -563,12 +564,12 @@ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles )
}



int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*> * pa, bool bRetainArcs )
{
    return NormalizeWithKbool( pa, bRetainArcs );
}


// Restore arcs to a polygon where they were replaced with steps
// If pa != NULL, also use polygons in pa array
//
@@ -1314,27 +1315,26 @@ void CPolyLine::Hatch()

// test to see if a point is inside polyline
//
bool CPolyLine::TestPointInside( int x, int y )
bool CPolyLine::TestPointInside( int px, int py )
{
    enum {
        MAXPTS = 100
    };
    if( !GetClosed() )
        wxASSERT( 0 );

    // define line passing through (x,y), with slope = 2/3;
    // get intersection points
    double xx[MAXPTS], yy[MAXPTS];
    int    xx, yy;
    double slope = (double) 2.0 / 3.0;
    double a      = y - slope * x;
    double a      = py - slope * px;
    int    nloops = 0;
    int    npts;
    bool   inside = false;

    // make this a loop so if my homebrew algorithm screws up, we try it again
    do
    {
        // now find all intersection points of line with polyline sides
        npts   = 0;
        inside = false;
        for( int icont = 0; icont<GetNumContours(); icont++ )
        {
            int istart = GetContourStart( icont );
@@ -1347,7 +1347,7 @@ bool CPolyLine::TestPointInside( int x, int y )
                    ok = FindLineSegmentIntersection( a, slope,
                        corner[iend].x, corner[iend].y,
                        corner[istart].x, corner[istart].y,
                                                      side_style[corner.size() - 1],
                        side_style[iend],
                        &x, &y, &x2, &y2 );
                else
                    ok = FindLineSegmentIntersection( a, slope,
@@ -1357,17 +1357,23 @@ bool CPolyLine::TestPointInside( int x, int y )
                        &x, &y, &x2, &y2 );
                if( ok )
                {
                    xx[npts] = (int) x;
                    yy[npts] = (int) y;
                    xx = (int) x;
                    yy = (int) y;
                    if( xx == px && yy == py )
                        return FALSE; // (x,y) is on a side, call it outside
                    else if( xx > px )
                        inside = not inside;
                    npts++;
                    wxASSERT( npts<MAXPTS );    // overflow
                }
                if( ok == 2 )
                {
                    xx[npts] = (int) x2;
                    yy[npts] = (int) y2;
                    xx = (int) x2;
                    yy = (int) y2;
                    if( xx == px && yy == py )
                        return FALSE; // (x,y) is on a side, call it outside
                    else if( xx > px )
                        inside = not inside;
                    npts++;
                    wxASSERT( npts<MAXPTS );    // overflow
                }
            }
        }
@@ -1378,49 +1384,34 @@ bool CPolyLine::TestPointInside( int x, int y )

    wxASSERT( npts % 2==0 );  // odd number of intersection points, error

    // count intersection points to right of (x,y), if odd (x,y) is inside polyline
    int ncount = 0;
    for( int ip = 0; ip<npts; ip++ )
    {
        if( xx[ip] == x && yy[ip] == y )
            return FALSE; // (x,y) is on a side, call it outside
        else if( xx[ip] > x )
            ncount++;
    }

    if( ncount % 2 )
        return TRUE;
    else
        return FALSE;
    return inside;
}


// test to see if a point is inside polyline contour
//
bool CPolyLine::TestPointInsideContour( int icont, int x, int y )
bool CPolyLine::TestPointInsideContour( int icont, int px, int py )
{
    if( icont >= GetNumContours() )
        return FALSE;

    enum {
        MAXPTS = 100
    };
    if( !GetClosed() )
        wxASSERT( 0 );

// define line passing through (x,y), with slope = 2/3;
// get intersection points
    double xx[MAXPTS], yy[MAXPTS];
    int    xx, yy;
    double slope = (double) 2.0 / 3.0;
    double a      = y - slope * x;
    double a      = py - slope * px;
    int    nloops = 0;
    int    npts;
    bool   inside = false;

// make this a loop so if my homebrew algorithm screws up, we try it again
    do
    {
        // now find all intersection points of line with polyline sides
        npts   = 0;
        inside = false;
        int istart = GetContourStart( icont );
        int iend   = GetContourEnd( icont );
        for( int ic = istart; ic<=iend; ic++ )
@@ -1431,7 +1422,7 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y )
                ok = FindLineSegmentIntersection( a, slope,
                    corner[iend].x, corner[iend].y,
                    corner[istart].x, corner[istart].y,
                                                  side_style[corner.size() - 1],
                    side_style[iend],
                    &x, &y, &x2, &y2 );
            else
                ok = FindLineSegmentIntersection( a, slope,
@@ -1441,17 +1432,23 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y )
                    &x, &y, &x2, &y2 );
            if( ok )
            {
                xx[npts] = (int) x;
                yy[npts] = (int) y;
                xx = (int) x;
                yy = (int) y;
                npts++;
                wxASSERT( npts<MAXPTS );    // overflow
                if( xx == px && yy == py )
                    return FALSE; // (x,y) is on a side, call it outside
                else if( xx > px )
                    inside = not inside;
            }
            if( ok == 2 )
            {
                xx[npts] = (int) x2;
                yy[npts] = (int) y2;
                xx = (int) x2;
                yy = (int) y2;
                npts++;
                wxASSERT( npts<MAXPTS );    // overflow
                if( xx == px && yy == py )
                    return FALSE; // (x,y) is on a side, call it outside
                else if( xx > px )
                    inside = not inside;
            }
        }

@@ -1461,20 +1458,7 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y )

    wxASSERT( npts % 2==0 );  // odd number of intersection points, error

    // count intersection points to right of (x,y), if odd (x,y) is inside polyline
    int ncount = 0;
    for( int ip = 0; ip<npts; ip++ )
    {
        if( xx[ip] == x && yy[ip] == y )
            return FALSE; // (x,y) is on a side, call it outside
        else if( xx[ip] > x )
            ncount++;
    }

    if( ncount % 2 )
        return TRUE;
    else
        return FALSE;
    return inside;
}


@@ -1545,7 +1529,6 @@ void CPolyLine::SetEndContour( int ic, bool end_contour )
}



void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num )
{
    // get radius
+2 −2
Original line number Diff line number Diff line
@@ -47,10 +47,10 @@ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false );

#define to_int( x ) (int) round( (x) )
#ifndef min
#define min( x1, x2 ) ( (x1) > (x2) ) ? (x2) : (x1)
#define min( x1, x2 ) ( (x1) > (x2) ? (x2) : (x1) )
#endif
#ifndef max
#define max( x1, x2 ) ( (x1) > (x2) ) ? (x1) : (x2)
#define max( x1, x2 ) ( (x1) > (x2) ? (x1) : (x2) )
#endif

class CRect
+0 −1
Original line number Diff line number Diff line
@@ -639,7 +639,6 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
									   int * x, int * y, double * d )
{
	double a, b, dist;

	// first, test for intersection
	if( x1i == x1f && x2i == x2f )
	{
+355 −0
Original line number Diff line number Diff line
/////////////////////////////////////////////////////////////////////////////
// Name:        polygon_test_point_inside.cpp
/////////////////////////////////////////////////////////////////////////////

#include <math.h>
#include <vector>
#include "PolyLine.h"

using namespace std;

/* this algo uses the the Jordan curve theorem to find if a point is inside or outside a polygon:
  * It run a semi-infinite line horizontally (increasing x, fixed y)
  * out from the test point, and count how many edges it crosses.
  * At each crossing, the ray switches between inside and outside.
  * If odd nimber, the test point is inside the polygon
  * This is called the Jordan curve theorem, or sometimes referred to as the "even-odd" test.
 */

/* 2 versions are given.
 * the second version is GPL (currently used)
 * the first version is for explanations and tests (used to test the second version)
 * both use the same algorithm.
*/
#if 0

/* This text and the algorithm come from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
 *
 * PNPOLY - Point Inclusion in Polygon Test
 * W. Randolph Franklin (WRF)
 *
 * Table of Contents
 *
 * 1. The C Code <#The C Code>
 * 2. The Method <#The Method>
 * 3. Originality <#Originality>
 * 4. The Inequality Tests are Tricky <#The Inequality Tests are Tricky>
 * 5. C Semantics <#C Semantics>
 * 6. Point on a (Boundary) Edge <#Point on an Edge>
 * 7. Multiple Components and Holes <#Listing the Vertices>
 * 8. Testing Which One of Many Polygons Contains the Point <#Testing a
 *   Point Against Many Polygons>
 * 9. Explanation of /"for (i = 0, j = nvert-1; i < nvert; j = i++)"/
 *   <#Explanation>
 * 10. Fortran Code for the Point in Polygon Test <#Fortran Code for the
 *   Point in Polygon Test>
 * 11. Converting the Code to All Integers <#Converting the Code to All
 *   Integers>
 * 12. License to Use <#License to Use>
 *
 * The C Code
 *
 * Here is the code, for reference. Excluding lines with only braces, there
 * are only /7 lines/ of code.
 *
 * int pnpoly(int nvert, float *vertx, float *verty, float ref_pointX, float ref_pointY)
 * {
 * int i, j, c = 0;
 * for (i = 0, j = nvert-1; i < nvert; j = i++) {
 * if ( ((verty[i]>ref_pointY) != (verty[j]>ref_pointY)) &&
 *  (ref_pointX < (vertx[j]-vertx[i]) * (ref_pointY-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
 *    c = !c;
 * }
 * return c;
 * }
 *
 * Argument	Meaning
 * nvert 	Number of vertices in the polygon. Whether to repeat the first
 * vertex at the end is discussed below.
 * vertx, verty 	Arrays containing the x- and y-coordinates of the
 * polygon's vertices.
 * ref_pointX, ref_pointY	X- and y-coordinate of the test point.
 *
 *
 * The Method
 *
 * I run a semi-infinite ray horizontally (increasing x, fixed y) out from
 * the test point, and count how many edges it crosses. At each crossing,
 * the ray switches between inside and outside. This is called the /Jordan
 * curve theorem/.
 *
 * The case of the ray going thru a vertex is handled correctly via a
 * careful selection of inequalities. Don't mess with this code unless
 * you're familiar with the idea of /Simulation of Simplicity/. This
 * pretends to shift the ray infinitesimally to one side so that it either
 * clearly intersects, or clearly doesn't touch. Since this is merely a
 * conceptual, infinitesimal, shift, it never creates an intersection that
 * didn't exist before, and never destroys an intersection that clearly
 * existed before.
 *
 * The ray is tested against each edge thus:
 *
 * 1. Is the point in the half-plane below the extended edge? and
 * 2. Is the point's X coordinate within the edge's X-range?
 *
 * Handling endpoints here is tricky.
 *
 *
 * Originality
 *
 * I make no claim to having invented the idea. However in 1970, I did
 * produce the Fortran code given below on my own, and include it in a
 * package of cartographic SW publicly-distributed by David Douglas, Dept
 * of Geography, Simon Fraser U and U of Ottawa.
 *
 * Earlier implementations of point-in-polygon testing presumably exist,
 * tho the code might never have been released. Pointers to prior art,
 * especially publicly available code, are welcome. One early publication,
 * which doesn't handle the point on an edge, and has a typo, is this:
 *
 * M Shimrat, "Algorithm 112, Position of Point Relative to Polygon",
 *   /Comm. ACM/ 5(8), Aug 1962, p 434.
 *
 * A well-written recent summary is this:
 *
 * E Haines, /Point in Polygon Strategies/,
 *   http://www.acm.org/pubs/tog/editors/erich/ptinpoly/, 1994.
 *
 *
 * The Inequality Tests are Tricky
 *
 * If translating the program to another language, be sure to get the
 * inequalities in the conditional correct. They were carefully chosen to
 * make the program work correctly when the point is vertically below a vertex.
 *
 * Several people have thought that my program was wrong, when really
 * /they/ had gotten the inequalities wrong.
 *
 *
 * C Semantics
 *
 * My code uses the fact that, in the C language, when executing the code
 |a&&b|, if |a| is false, then |b| must not be evaluated. If your
 * compiler doesn't do this, then it's not implementing C, and you will get
 * a divide-by-zero, i.a., when the test point is vertically in line with a
 * vertical edge. When translating this code to another language with
 * different semantics, then you must implement this test explicitly.
 *
 *
 * Point on a (Boundary) Edge
 *
 * PNPOLY partitions the plane into points inside the polygon and points
 * outside the polygon. Points that are on the boundary are classified as
 * either inside or outside.
 *
 * 1.
 *
 *   Any particular point is always classified consistently the same
 *   way. In the following figure, consider what PNPOLY would say when
 *   the red point, /P/, is tested against the two triangles, /T_L /
 *   and /T_R /. Depending on internal roundoff errors, PNPOLY may say
 *   that /P/ is in /T_L / or in /T_R /. However it will always give
 *   the same answer when /P/ is tested against those triangles. That
 *   is, if PNPOLY finds that /P/ is in /T_L /, then it will find that
 *   /P/ is not /T_R /. If PNPOLY finds that /P/ is not in /T_L /, then
 *   it will find that /P/ is in /T_R /.
 *
 * 2. If you want to know when a point is exactly on the boundary, you
 *   need another program. This is only one of many functions that
 *   PNPOLY lacks; it also doesn't predict tomorrow's weather. You are
 *   free to extend PNPOLY's source code.
 *
 * 3. The first reason for this is the numerical analysis position that
 *   you should not be testing exact equality unless your input is
 *   exact. Even then, computational roundoff error would often make
 *   the result wrong.
 *
 * 4. The second reason is that, if you partition a region of the plane
 *   into polygons, i.e., form a planar graph, then PNPOLY will locate
 *   each point into exactly one polygon. In other words, PNPOLY
 *   considers each polygon to be topologically a semi-open set. This
 *   makes things simpler, i.e., causes fewer special cases, if you use
 *   PNPOLY as part of a larger system. Examples of this include
 *   locating a point in a planar graph, and intersecting two planar
 *   graphs.
 *
 *
 * Explanation of /"for (i = 0, j = nvert-1; i < nvert; j = i++)"/
 *
 * The intention is to execute the loop for each i from 0 to nvert-1. For
 * each iteration, j is i-1. However that wraps, so if i=0 then j=nvert-1.
 * Therefore the current edge runs between verts j and i, and the loop is
 * done once per edge. In detail:
 *
 * 1. Start by setting i and j:
 *   i = 0
 *   j = nvert-1
 * 2. If i<nvert is false then exit the loop.
 * 3. Do the loop body.
 * 4. Set j=i and then
 *   add 1 to i and then
 * 5. Go back to step 2.
 *
 *
 *
 * Converting the Code to All Integers
 *
 * If you want to convert the code from floats to integers, consider these
 * issues.
 *
 * 1. On many current processors floats are at least as fast as ints.
 * 2. If you move the denominator over to the other side of the
 *   inequality, remember that, when the denominator is negative, the
 *   inequality will flip.
 * 3. If coordinates are large enough, the multiplication will silently
 *   overflow.
 *
 *
 * License to Use
 * Copyright (c) 1970-2003, Wm. Randolph Franklin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * 1. Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimers.
 * 2. Redistributions in binary form must reproduce the above copyright
 *   notice in the documentation and/or other materials provided with
 *   the distribution.
 * 3. The name of W. Randolph Franklin may not be used to endorse or
 *   promote products derived from this Software without specific prior
 *   written permission.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 *
 * Copyright © 1994-2006, W Randolph Franklin (WRF)
 * <http://wrfranklin.org/> You may use my material for non-profit research
 * and education, provided that you credit me, and link back to my home page.
 * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html,
 *     05/20/2008 20:36:42
 */

bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
                             int                   istart,
                             int                   iend,
                             int                   refx,
                             int                   refy )

/** Function TestPointInsidePolygon
 * test if a point is inside or outside a polygon.
 * @param aPolysList: the list of polygons
 * @param istart: the starting point of a given polygon in m_FilledPolysList.
 * @param iend: the ending point of the polygon in m_FilledPolysList.
 * @param refx, refy: the point coordinate to test
 * @return true if the point is inside, false for outside
 */
{
    double ref_pointX = refx;
    double ref_pointY = refy;

    bool   inside = false;

    for( int ii = istart, jj = iend; ii <= iend; jj = ii++ )
    {
        double seg_startX, seg_startY;  // starting point for the segment to test
        seg_startX = aPolysList[ii].x;
        seg_startY = aPolysList[ii].y;
        double seg_endX, seg_endY;      // ending point for the segment to test
        seg_endX = aPolysList[jj].x;
        seg_endY = aPolysList[jj].y;
        if( ( ( seg_startY > ref_pointY ) != (seg_endY > ref_pointY ) )
           && (ref_pointX <
               (seg_endX -
                seg_startX) * (ref_pointY - seg_startY) / (seg_endY - seg_startY) + seg_startX) )
            inside = not inside;
    }

    return inside;
}


#else

/* this algo come from freePCB.
 */

bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
                             int                   istart,
                             int                   iend,
                             int                   refx,
                             int                   refy )

/** Function TestPointInsidePolygon
 * test if a point is inside or outside a polygon.
 * if a point is on a  outline segment, it is considered outside the polygon
 * @param aPolysList: the list of polygons
 * @param istart: the starting point of a given polygon in m_FilledPolysList.
 * @param iend: the ending point of the polygon in m_FilledPolysList.
 * @param refx,refy: the point coordinate to test
 * @return true if the point is inside, false for outside
 * this algorithm come from FreePCB.
 */
{
    #define OUTSIDE_IF_ON_SIDE 0    // = 1 if we consider point on a side outside the polygon
    // define line passing through (x,y), with slope = 0 (horizontal line)
    // get intersection points
    // count intersection points to right of (x,y), if odd (x,y) is inside polyline
    int    xx, yy;
    double slope = 0;
    double a      = refy - slope * refx;
    int    ics, ice;
    bool   inside = false;

    // find all intersection points of line with polyline sides
    for( ics = istart, ice = iend; ics <= iend; ice = ics++ )
    {
        double x, y, x2, y2;
        int    ok = FindLineSegmentIntersection( a, slope,
            aPolysList[ics].x, aPolysList[ics].y,
            aPolysList[ice].x, aPolysList[ice].y,
            0,
            &x, &y,
            &x2, &y2 );
        if( ok )
        {
            xx = (int) x;
            yy = (int) y;
#if OUTSIDE_IF_ON_SIDE
            if( xx == refx && yy == refy )
                return false; // (x,y) is on a side, call it outside
            else
#endif
            if( xx > refx )
                inside = not inside;
        }
        if( ok == 2 )
        {
            xx = (int) x2;
            yy = (int) y2;
#if OUTSIDE_IF_ON_SIDE
            if( xx == refx && yy == refy )
                return false; // (x,y) is on a side, call it outside
            else
#endif
            if( xx > refx )
                inside = not inside;
        }
    }

    return inside;
}


#endif
Loading