Move connectivity algo to collision-based routines.
Fixes https://gitlab.com/kicad/code/kicad/issues/1800 Fixes https://gitlab.com/kicad/code/kicad/issues/1769
This commit is contained in:
parent
a2ca8cf413
commit
90f6edad61
|
@ -9,7 +9,6 @@ set( KIMATH_SRCS
|
|||
src/geometry/convex_hull.cpp
|
||||
src/geometry/direction_45.cpp
|
||||
src/geometry/geometry_utils.cpp
|
||||
src/geometry/poly_grid_partition.cpp
|
||||
src/geometry/seg.cpp
|
||||
src/geometry/shape.cpp
|
||||
src/geometry/shape_arc.cpp
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
/*
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016-2017 CERN
|
||||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef __POLY_GRID_PARTITION_H
|
||||
#define __POLY_GRID_PARTITION_H
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <math/vector2d.h>
|
||||
|
||||
/**
|
||||
* Provide a fast test for point inside polygon.
|
||||
*
|
||||
* Takes a large poly and splits it into a grid of rectangular cells, forming a spatial hash table.
|
||||
* Each cell contains only the edges that 'touch it' (any point of the edge belongs to the cell).
|
||||
* Edges can be marked as leading or trailing. Leading edge indicates that space to the left of
|
||||
* it (x-wise) is outside the polygon. Trailing edge, conversely, means space to the right is
|
||||
* outside the polygon.
|
||||
*
|
||||
* The point inside check for point (p) works as follows:
|
||||
* - determine the cell coordinates of (p) (poly2grid)
|
||||
* - find the matching grid cell ( O(0), if the cell coordinates are outside the range, the point
|
||||
* is not in the polygon ).
|
||||
* - if the cell contains edges, find the first edge to the left or right of the point, whichever
|
||||
* comes first.
|
||||
* - if the edge to the left is the 'lead edge', the point is inside. if it's a trailing edge, the
|
||||
* point is outside.
|
||||
* - idem for the edge to the right of (p), just reverse the edge types.
|
||||
* - if the cell doesn't contain any edges, scan horizontal cells to the left and right (switching
|
||||
* sides with each iteration) until an edge if found.
|
||||
*
|
||||
* @note: The rescale_trunc() function is used for grid<->world coordinate conversion because it
|
||||
* rounds towards 0 (not to nearest). It's important as rounding to nearest (which the
|
||||
* standard rescale() function does) will shift the grid by half a cell.
|
||||
*/
|
||||
|
||||
class POLY_GRID_PARTITION
|
||||
{
|
||||
public:
|
||||
POLY_GRID_PARTITION( const SHAPE_LINE_CHAIN& aPolyOutline, int gridSize );
|
||||
|
||||
int ContainsPoint( const VECTOR2I& aP, int aClearance = 0 );
|
||||
|
||||
const BOX2I& BBox() const
|
||||
{
|
||||
return m_bbox;
|
||||
}
|
||||
|
||||
private:
|
||||
enum HASH_FLAG
|
||||
{
|
||||
LEAD_EDGE = 1,
|
||||
TRAIL_EDGE = 2,
|
||||
};
|
||||
|
||||
using EDGE_LIST = std::vector<int>;
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine( std::size_t& seed, const T& v )
|
||||
{
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher( v ) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
struct segsEqual
|
||||
{
|
||||
bool operator()( const SEG& a, const SEG& b ) const
|
||||
{
|
||||
return (a.A == b.A && a.B == b.B) || (a.A == b.B && a.B == b.A);
|
||||
}
|
||||
};
|
||||
|
||||
struct segHash
|
||||
{
|
||||
std::size_t operator()( const SEG& a ) const
|
||||
{
|
||||
return a.A.x + a.B.x + a.A.y + a.B.y;
|
||||
}
|
||||
};
|
||||
|
||||
int containsPoint( const VECTOR2I& aP, bool debug = false ) const;
|
||||
|
||||
bool checkClearance( const VECTOR2I& aP, int aClearance );
|
||||
|
||||
int rescale_trunc( int aNumerator, int aValue, int aDenominator ) const;
|
||||
|
||||
// converts grid cell coordinates to the polygon coordinates
|
||||
const VECTOR2I grid2poly( const VECTOR2I& p ) const;
|
||||
|
||||
int grid2polyX( int x ) const;
|
||||
|
||||
int grid2polyY( int y ) const;
|
||||
|
||||
const VECTOR2I poly2grid( const VECTOR2I& p ) const;
|
||||
|
||||
int poly2gridX( int x ) const;
|
||||
|
||||
int poly2gridY( int y ) const;
|
||||
|
||||
void build( const SHAPE_LINE_CHAIN& aPolyOutline, int gridSize );
|
||||
|
||||
bool inRange( int v1, int v2, int x ) const;
|
||||
|
||||
struct SCAN_STATE
|
||||
{
|
||||
SCAN_STATE()
|
||||
{
|
||||
dist_prev = INT_MAX;
|
||||
dist_max = INT_MAX;
|
||||
nearest = -1;
|
||||
nearest_prev = -1;
|
||||
};
|
||||
|
||||
int dist_prev;
|
||||
int dist_max;
|
||||
int nearest_prev;
|
||||
int nearest;
|
||||
};
|
||||
|
||||
void scanCell( SCAN_STATE& state, const EDGE_LIST& cell, const VECTOR2I& aP, int cx,
|
||||
int cy ) const;
|
||||
|
||||
private:
|
||||
int m_gridSize;
|
||||
SHAPE_LINE_CHAIN m_outline;
|
||||
BOX2I m_bbox;
|
||||
std::vector<int> m_flags;
|
||||
std::vector<EDGE_LIST> m_grid;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -101,9 +101,8 @@ public:
|
|||
case 0: return parent->m_vertices[a];
|
||||
case 1: return parent->m_vertices[b];
|
||||
case 2: return parent->m_vertices[c];
|
||||
default: assert(false);
|
||||
default: wxCHECK( false, VECTOR2I() );
|
||||
}
|
||||
return VECTOR2I(0, 0);
|
||||
}
|
||||
|
||||
virtual const SEG GetSegment( int aIndex ) const override
|
||||
|
@ -113,16 +112,16 @@ public:
|
|||
case 0: return SEG( parent->m_vertices[a], parent->m_vertices[b] );
|
||||
case 1: return SEG( parent->m_vertices[b], parent->m_vertices[c] );
|
||||
case 2: return SEG( parent->m_vertices[c], parent->m_vertices[a] );
|
||||
default: assert(false);
|
||||
default: wxCHECK( false, SEG() );
|
||||
}
|
||||
return SEG();
|
||||
}
|
||||
|
||||
virtual size_t GetPointCount() const override { return 3; }
|
||||
virtual size_t GetSegmentCount() const override { return 3; }
|
||||
|
||||
|
||||
int a, b, c;
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
TRIANGULATED_POLYGON* parent;
|
||||
};
|
||||
|
||||
|
@ -153,15 +152,10 @@ public:
|
|||
m_vertices.push_back( aP );
|
||||
}
|
||||
|
||||
size_t GetTriangleCount() const
|
||||
{
|
||||
return m_triangles.size();
|
||||
}
|
||||
size_t GetTriangleCount() const { return m_triangles.size(); }
|
||||
|
||||
std::deque<TRI>& Triangles()
|
||||
{
|
||||
return m_triangles;
|
||||
}
|
||||
std::deque<TRI>& Triangles() { return m_triangles; }
|
||||
const std::deque<TRI>& Triangles() const { return m_triangles; }
|
||||
|
||||
size_t GetVertexCount() const
|
||||
{
|
||||
|
@ -170,7 +164,7 @@ public:
|
|||
|
||||
void Move( const VECTOR2I& aVec )
|
||||
{
|
||||
for( auto& vertex : m_vertices )
|
||||
for( VECTOR2I& vertex : m_vertices )
|
||||
vertex += aVec;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,466 +0,0 @@
|
|||
/*
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016-2017 CERN
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <geometry/poly_grid_partition.h>
|
||||
#include <math/util.h>
|
||||
|
||||
POLY_GRID_PARTITION::POLY_GRID_PARTITION( const SHAPE_LINE_CHAIN& aPolyOutline, int gridSize )
|
||||
{
|
||||
build( aPolyOutline, gridSize );
|
||||
}
|
||||
|
||||
|
||||
int POLY_GRID_PARTITION::ContainsPoint( const VECTOR2I& aP, int aClearance ) // const
|
||||
{
|
||||
if( containsPoint( aP ) )
|
||||
return 1;
|
||||
|
||||
if( aClearance > 0 )
|
||||
return checkClearance( aP, aClearance );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int POLY_GRID_PARTITION::containsPoint( const VECTOR2I& aP, bool debug ) const
|
||||
{
|
||||
const auto gridPoint = poly2grid( aP );
|
||||
|
||||
if( !m_bbox.Contains( aP ) )
|
||||
return 0;
|
||||
|
||||
SCAN_STATE state;
|
||||
const EDGE_LIST& cell = m_grid[m_gridSize * gridPoint.y + gridPoint.x];
|
||||
|
||||
scanCell( state, cell, aP, gridPoint.x, gridPoint.y );
|
||||
|
||||
if( state.nearest < 0 )
|
||||
{
|
||||
state = SCAN_STATE();
|
||||
|
||||
for( int d = 1; d <= m_gridSize; d++ )
|
||||
{
|
||||
int xl = gridPoint.x - d;
|
||||
int xh = gridPoint.x + d;
|
||||
|
||||
if( xl >= 0 )
|
||||
{
|
||||
const EDGE_LIST& cell2 = m_grid[m_gridSize * gridPoint.y + xl];
|
||||
scanCell( state, cell2, aP, xl, gridPoint.y );
|
||||
|
||||
if( state.nearest >= 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
if( xh < m_gridSize )
|
||||
{
|
||||
const EDGE_LIST& cell2 = m_grid[m_gridSize * gridPoint.y + xh];
|
||||
scanCell( state, cell2, aP, xh, gridPoint.y );
|
||||
|
||||
if( state.nearest >= 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TOM_EXTRA_VERBOSE
|
||||
printf( "Nearest: %d prev: %d dmax %d\n", state.nearest, state.nearest_prev, state.dist_max );
|
||||
#endif
|
||||
|
||||
if( state.nearest < 0 )
|
||||
return 0;
|
||||
|
||||
if( state.dist_max == 0 )
|
||||
return 1;
|
||||
|
||||
|
||||
// special case for diagonal 'slits', e.g. two segments that partially overlap each other.
|
||||
// Just love handling degeneracy... As I can't find any reliable way of fixing it for the moment,
|
||||
// let's fall back to the good old O(N) point-in-polygon test
|
||||
if( state.nearest_prev >= 0 && state.dist_max == state.dist_prev )
|
||||
{
|
||||
int d = std::abs( state.nearest_prev - state.nearest );
|
||||
|
||||
if( ( d == 1 ) && ( ( m_flags[state.nearest_prev] & m_flags[state.nearest] ) == 0 ) )
|
||||
{
|
||||
return m_outline.PointInside( aP );
|
||||
}
|
||||
}
|
||||
|
||||
if( state.dist_max > 0 )
|
||||
{
|
||||
return m_flags[state.nearest] & LEAD_EDGE ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_flags[state.nearest] & TRAIL_EDGE ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool POLY_GRID_PARTITION::checkClearance( const VECTOR2I& aP, int aClearance )
|
||||
{
|
||||
int gx0 = poly2gridX( aP.x - aClearance - 1 );
|
||||
int gx1 = poly2gridX( aP.x + aClearance + 1 );
|
||||
int gy0 = poly2gridY( aP.y - aClearance - 1 );
|
||||
int gy1 = poly2gridY( aP.y + aClearance + 1 );
|
||||
|
||||
using ecoord = VECTOR2I::extended_type;
|
||||
|
||||
ecoord dist = (ecoord) aClearance * aClearance;
|
||||
|
||||
for( int gx = gx0; gx <= gx1; gx++ )
|
||||
{
|
||||
for( int gy = gy0; gy <= gy1; gy++ )
|
||||
{
|
||||
const auto& cell = m_grid[m_gridSize * gy + gx];
|
||||
for( auto index : cell )
|
||||
{
|
||||
const auto& seg = m_outline.Segment( index );
|
||||
|
||||
if( seg.SquaredDistance( aP ) <= dist )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int POLY_GRID_PARTITION::rescale_trunc( int aNumerator, int aValue, int aDenominator ) const
|
||||
{
|
||||
int64_t numerator = (int64_t) aNumerator * (int64_t) aValue;
|
||||
|
||||
wxASSERT( aDenominator != 0 );
|
||||
|
||||
if( aDenominator == 0 ) // Avoid crash when divide by 0
|
||||
aDenominator = 1;
|
||||
|
||||
return numerator / aDenominator;
|
||||
}
|
||||
|
||||
|
||||
// convertes grid cell coordinates to the polygon coordinates
|
||||
const VECTOR2I POLY_GRID_PARTITION::grid2poly( const VECTOR2I& p ) const
|
||||
{
|
||||
int px = rescale_trunc( p.x, m_bbox.GetWidth(), m_gridSize ) + m_bbox.GetPosition().x;
|
||||
int py = rescale_trunc( p.y, m_bbox.GetHeight(), m_gridSize ) + m_bbox.GetPosition().y;
|
||||
return VECTOR2I( px, py );
|
||||
}
|
||||
|
||||
|
||||
int POLY_GRID_PARTITION::grid2polyX( int x ) const
|
||||
{
|
||||
return rescale_trunc( x, m_bbox.GetWidth(), m_gridSize ) + m_bbox.GetPosition().x;
|
||||
}
|
||||
|
||||
|
||||
int POLY_GRID_PARTITION::grid2polyY( int y ) const
|
||||
{
|
||||
return rescale_trunc( y, m_bbox.GetHeight(), m_gridSize ) + m_bbox.GetPosition().y;
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I POLY_GRID_PARTITION::poly2grid( const VECTOR2I& p ) const
|
||||
{
|
||||
int px = rescale_trunc( p.x - m_bbox.GetPosition().x, m_gridSize, m_bbox.GetWidth() );
|
||||
int py = rescale_trunc( p.y - m_bbox.GetPosition().y, m_gridSize, m_bbox.GetHeight() );
|
||||
|
||||
if( px < 0 )
|
||||
px = 0;
|
||||
|
||||
if( px >= m_gridSize )
|
||||
px = m_gridSize - 1;
|
||||
|
||||
if( py < 0 )
|
||||
py = 0;
|
||||
|
||||
if( py >= m_gridSize )
|
||||
py = m_gridSize - 1;
|
||||
|
||||
return VECTOR2I( px, py );
|
||||
}
|
||||
|
||||
|
||||
int POLY_GRID_PARTITION::poly2gridX( int x ) const
|
||||
{
|
||||
int px = rescale_trunc( x - m_bbox.GetPosition().x, m_gridSize, m_bbox.GetWidth() );
|
||||
|
||||
if( px < 0 )
|
||||
px = 0;
|
||||
|
||||
if( px >= m_gridSize )
|
||||
px = m_gridSize - 1;
|
||||
|
||||
return px;
|
||||
}
|
||||
|
||||
|
||||
int POLY_GRID_PARTITION::poly2gridY( int y ) const
|
||||
{
|
||||
int py = rescale_trunc( y - m_bbox.GetPosition().y, m_gridSize, m_bbox.GetHeight() );
|
||||
|
||||
if( py < 0 )
|
||||
py = 0;
|
||||
|
||||
if( py >= m_gridSize )
|
||||
py = m_gridSize - 1;
|
||||
|
||||
return py;
|
||||
}
|
||||
|
||||
|
||||
void POLY_GRID_PARTITION::build( const SHAPE_LINE_CHAIN& aPolyOutline, int gridSize )
|
||||
{
|
||||
m_outline = aPolyOutline;
|
||||
|
||||
//if (orientation(m_outline) < 0)
|
||||
// m_outline = m_outline.Reverse();
|
||||
|
||||
m_bbox = m_outline.BBox();
|
||||
m_gridSize = gridSize;
|
||||
|
||||
m_outline.SetClosed( true );
|
||||
|
||||
m_grid.reserve( gridSize * gridSize );
|
||||
|
||||
for( int y = 0; y < gridSize; y++ )
|
||||
{
|
||||
for( int x = 0; x < gridSize; x++ )
|
||||
{
|
||||
m_grid.emplace_back();
|
||||
}
|
||||
}
|
||||
|
||||
VECTOR2I ref_v( 0, 1 );
|
||||
VECTOR2I ref_h( 0, 1 );
|
||||
|
||||
m_flags.reserve( m_outline.SegmentCount() );
|
||||
|
||||
std::unordered_map<SEG, int, segHash, segsEqual> edgeSet;
|
||||
|
||||
for( int i = 0; i < m_outline.SegmentCount(); i++ )
|
||||
{
|
||||
SEG edge = m_outline.Segment( i );
|
||||
|
||||
if( edgeSet.find( edge ) == edgeSet.end() )
|
||||
{
|
||||
edgeSet[edge] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
edgeSet[edge]++;
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < m_outline.SegmentCount(); i++ )
|
||||
{
|
||||
auto edge = m_outline.Segment( i );
|
||||
auto dir = edge.B - edge.A;
|
||||
int flags = 0;
|
||||
|
||||
|
||||
if( dir.y == 0 )
|
||||
{
|
||||
flags = 0;
|
||||
}
|
||||
else if( edgeSet[edge] == 1 )
|
||||
{
|
||||
if( dir.Dot( ref_h ) < 0 )
|
||||
{
|
||||
flags |= LEAD_EDGE;
|
||||
}
|
||||
else if( dir.Dot( ref_h ) > 0 )
|
||||
{
|
||||
flags |= TRAIL_EDGE;
|
||||
}
|
||||
}
|
||||
|
||||
m_flags.push_back( flags );
|
||||
|
||||
if( edge.A.y == edge.B.y )
|
||||
continue;
|
||||
|
||||
std::set<int> indices;
|
||||
|
||||
indices.insert( m_gridSize * poly2gridY( edge.A.y ) + poly2gridX( edge.A.x ) );
|
||||
indices.insert( m_gridSize * poly2gridY( edge.B.y ) + poly2gridX( edge.B.x ) );
|
||||
|
||||
if( edge.A.x > edge.B.x )
|
||||
std::swap( edge.A, edge.B );
|
||||
|
||||
dir = edge.B - edge.A;
|
||||
|
||||
if( dir.x != 0 )
|
||||
{
|
||||
int gx0 = poly2gridX( edge.A.x );
|
||||
int gx1 = poly2gridX( edge.B.x );
|
||||
|
||||
for( int x = gx0; x <= gx1; x++ )
|
||||
{
|
||||
int px = grid2polyX( x );
|
||||
int py = ( edge.A.y + rescale_trunc( dir.y, px - edge.A.x, dir.x ) );
|
||||
int yy = poly2gridY( py );
|
||||
|
||||
indices.insert( m_gridSize * yy + x );
|
||||
|
||||
if( x > 0 )
|
||||
indices.insert( m_gridSize * yy + x - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
if( edge.A.y > edge.B.y )
|
||||
std::swap( edge.A, edge.B );
|
||||
|
||||
dir = edge.B - edge.A;
|
||||
|
||||
if( dir.y != 0 )
|
||||
{
|
||||
int gy0 = poly2gridY( edge.A.y );
|
||||
int gy1 = poly2gridY( edge.B.y );
|
||||
|
||||
for( int y = gy0; y <= gy1; y++ )
|
||||
{
|
||||
int py = grid2polyY( y );
|
||||
int px = ( edge.A.x + rescale_trunc( dir.x, py - edge.A.y, dir.y ) );
|
||||
int xx = poly2gridX( px );
|
||||
|
||||
indices.insert( m_gridSize * y + xx );
|
||||
|
||||
if( y > 0 )
|
||||
indices.insert( m_gridSize * ( y - 1 ) + xx );
|
||||
}
|
||||
}
|
||||
|
||||
for( auto idx : indices )
|
||||
m_grid[idx].push_back( i );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void POLY_GRID_PARTITION::scanCell( SCAN_STATE& state, const EDGE_LIST& cell, const VECTOR2I& aP,
|
||||
int cx, int cy ) const
|
||||
{
|
||||
int cx0 = grid2polyX( cx );
|
||||
int cx1 = grid2polyX( cx + 1 );
|
||||
|
||||
#ifdef TOM_EXTRA_VERBOSE
|
||||
printf( "Scan %d %d\n", cx, cy );
|
||||
#endif
|
||||
|
||||
for( auto index : cell )
|
||||
{
|
||||
const SEG& edge = m_outline.CSegment( index );
|
||||
|
||||
|
||||
if( m_flags[index] == 0 )
|
||||
{
|
||||
if( aP.y == edge.A.y
|
||||
&& inRange( edge.A.x, edge.B.x, aP.x ) ) // we belong to the outline
|
||||
{
|
||||
state.nearest = index;
|
||||
state.dist_max = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( inRange( edge.A.y, edge.B.y, aP.y ) )
|
||||
{
|
||||
#ifdef TOM_EXTRA_VERBOSE
|
||||
printf( "Test edge: %d [%d %d %d %d] p %d %d flags %d\n", index, edge.A.x, edge.A.y,
|
||||
edge.B.x, edge.B.y, aP.x, aP.y );
|
||||
#endif
|
||||
int dist = 0;
|
||||
int x0;
|
||||
if( edge.A.y == aP.y )
|
||||
{
|
||||
x0 = edge.A.x;
|
||||
}
|
||||
else if( edge.B.y == aP.y )
|
||||
{
|
||||
x0 = edge.B.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
x0 = edge.A.x
|
||||
+ rescale( ( edge.B.x - edge.A.x ), ( aP.y - edge.A.y ),
|
||||
( edge.B.y - edge.A.y ) );
|
||||
}
|
||||
|
||||
|
||||
dist = aP.x - x0;
|
||||
|
||||
#ifdef TOM_EXTRA_VERBOSE
|
||||
printf( " x0 %d dist %d [%s]\n", x0, dist,
|
||||
x0 < cx0 || x0 > cx1 ? "outside" : "inside" );
|
||||
#endif
|
||||
|
||||
if( x0 < cx0 || x0 > cx1 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if( dist == 0 )
|
||||
{
|
||||
if( state.nearest_prev < 0 || state.nearest != index )
|
||||
{
|
||||
state.dist_prev = state.dist_max;
|
||||
state.nearest_prev = state.nearest;
|
||||
}
|
||||
|
||||
state.nearest = index;
|
||||
state.dist_max = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if( dist != 0 && std::abs( dist ) <= std::abs( state.dist_max ) )
|
||||
{
|
||||
if( state.nearest_prev < 0 || state.nearest != index )
|
||||
{
|
||||
state.dist_prev = state.dist_max;
|
||||
state.nearest_prev = state.nearest;
|
||||
}
|
||||
|
||||
state.dist_max = dist;
|
||||
state.nearest = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool POLY_GRID_PARTITION::inRange( int v1, int v2, int x ) const
|
||||
{
|
||||
if( v1 < v2 )
|
||||
{
|
||||
return x >= v1 && x <= v2;
|
||||
}
|
||||
|
||||
return x >= v2 && x <= v1;
|
||||
}
|
|
@ -2464,7 +2464,7 @@ size_t SHAPE_POLY_SET::GetIndexableSubshapeCount() const
|
|||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET:: GetIndexableSubshapes( std::vector<SHAPE*>& aSubshapes )
|
||||
void SHAPE_POLY_SET::GetIndexableSubshapes( std::vector<SHAPE*>& aSubshapes )
|
||||
{
|
||||
aSubshapes.reserve( GetIndexableSubshapeCount() );
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016-2018 CERN
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
|
@ -604,7 +604,7 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE* aZone, PCB_LAYER_ID
|
|||
|
||||
void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones )
|
||||
{
|
||||
for( auto& z : aZones )
|
||||
for( CN_ZONE_ISOLATED_ISLAND_LIST& z : aZones )
|
||||
{
|
||||
Remove( z.m_zone );
|
||||
Add( z.m_zone );
|
||||
|
@ -672,34 +672,15 @@ void CN_VISITOR::checkZoneItemConnection( CN_ZONE_LAYER* aZoneLayer, CN_ITEM* aI
|
|||
if( aZoneLayer->Net() != aItem->Net() && !aItem->CanChangeNet() )
|
||||
return;
|
||||
|
||||
if( !aZoneLayer->BBox().Intersects( aItem->BBox() ) )
|
||||
return;
|
||||
|
||||
int accuracy = 0;
|
||||
|
||||
if( aItem->Parent()->Type() == PCB_VIA_T
|
||||
|| aItem->Parent()->Type() == PCB_TRACE_T
|
||||
|| aItem->Parent()->Type() == PCB_ARC_T )
|
||||
if( aZoneLayer->Collide( aItem->Parent()->GetEffectiveShape( aZoneLayer->GetLayer() ).get() ) )
|
||||
{
|
||||
accuracy = ( static_cast<PCB_TRACK*>( aItem->Parent() )->GetWidth() + 1 ) / 2;
|
||||
}
|
||||
|
||||
for( int i = 0; i < aItem->AnchorCount(); ++i )
|
||||
{
|
||||
if( aZoneLayer->ContainsPoint( aItem->GetAnchor( i ), accuracy ) )
|
||||
{
|
||||
aZoneLayer->Connect( aItem );
|
||||
aItem->Connect( aZoneLayer );
|
||||
return;
|
||||
}
|
||||
aZoneLayer->Connect( aItem );
|
||||
aItem->Connect( aZoneLayer );
|
||||
}
|
||||
}
|
||||
|
||||
void CN_VISITOR::checkZoneZoneConnection( CN_ZONE_LAYER* aZoneLayerA, CN_ZONE_LAYER* aZoneLayerB )
|
||||
{
|
||||
const ZONE* zoneA = static_cast<const ZONE*>( aZoneLayerA->Parent() );
|
||||
const ZONE* zoneB = static_cast<const ZONE*>( aZoneLayerB->Parent() );
|
||||
|
||||
if( aZoneLayerA->Layer() != aZoneLayerB->Layer() )
|
||||
return;
|
||||
|
||||
|
@ -709,38 +690,15 @@ void CN_VISITOR::checkZoneZoneConnection( CN_ZONE_LAYER* aZoneLayerA, CN_ZONE_LA
|
|||
const BOX2I& boxA = aZoneLayerA->BBox();
|
||||
const BOX2I& boxB = aZoneLayerB->BBox();
|
||||
|
||||
if( !boxA.Intersects( boxB ) )
|
||||
return;
|
||||
|
||||
PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aZoneLayerA->Layer() );
|
||||
|
||||
const SHAPE_LINE_CHAIN& outline =
|
||||
zoneA->GetFilledPolysList( layer ).COutline( aZoneLayerA->SubpolyIndex() );
|
||||
|
||||
for( int i = 0; i < outline.PointCount(); i++ )
|
||||
if( aZoneLayerA->Collide( aZoneLayerB->Parent()->GetEffectiveShape( layer ).get() ) )
|
||||
{
|
||||
if( !boxB.Contains( outline.CPoint( i ) ) )
|
||||
continue;
|
||||
|
||||
if( aZoneLayerB->ContainsPoint( outline.CPoint( i ) ) )
|
||||
{
|
||||
aZoneLayerA->Connect( aZoneLayerB );
|
||||
aZoneLayerB->Connect( aZoneLayerA );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const SHAPE_LINE_CHAIN& outline2 =
|
||||
zoneB->GetFilledPolysList( layer ).COutline( aZoneLayerB->SubpolyIndex() );
|
||||
|
||||
for( int i = 0; i < outline2.PointCount(); i++ )
|
||||
{
|
||||
if( !boxA.Contains( outline2.CPoint( i ) ) )
|
||||
continue;
|
||||
|
||||
if( aZoneLayerA->ContainsPoint( outline2.CPoint( i ) ) )
|
||||
{
|
||||
aZoneLayerA->Connect( aZoneLayerB );
|
||||
aZoneLayerB->Connect( aZoneLayerA );
|
||||
return;
|
||||
}
|
||||
aZoneLayerA->Connect( aZoneLayerB );
|
||||
aZoneLayerB->Connect( aZoneLayerA );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include <zone.h>
|
||||
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/poly_grid_partition.h>
|
||||
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
|
|
@ -39,8 +39,6 @@ int CN_ITEM::AnchorCount() const
|
|||
|
||||
switch( m_parent->Type() )
|
||||
{
|
||||
case PCB_PAD_T:
|
||||
return 5; // center, north, south, east and west
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
return 2; // start and end
|
||||
|
@ -52,89 +50,14 @@ int CN_ITEM::AnchorCount() const
|
|||
|
||||
const VECTOR2I CN_ITEM::GetAnchor( int n ) const
|
||||
{
|
||||
VECTOR2I pt0;
|
||||
|
||||
if( !m_valid )
|
||||
return pt0;
|
||||
return VECTOR2I();
|
||||
|
||||
switch( m_parent->Type() )
|
||||
{
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( m_parent );
|
||||
return static_cast<PAD*>( m_parent )->GetPosition();
|
||||
|
||||
if( n == 0 )
|
||||
return VECTOR2I( pad->GetPosition() );
|
||||
|
||||
// ShapePos() is the geometric center (not anchor) for the pad
|
||||
pt0 = pad->ShapePos();
|
||||
VECTOR2I pt1 = pt0;
|
||||
|
||||
switch( pad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE::TRAPEZOID:
|
||||
// Because the trap delta is applied as +1/2 at one end and -1/2 at the other,
|
||||
// the midpoint is actually unchanged. Therefore all the cardinal points are
|
||||
// the same as for a rectangle.
|
||||
KI_FALLTHROUGH;
|
||||
|
||||
case PAD_SHAPE::RECT:
|
||||
case PAD_SHAPE::CIRCLE:
|
||||
case PAD_SHAPE::OVAL:
|
||||
case PAD_SHAPE::ROUNDRECT:
|
||||
case PAD_SHAPE::CHAMFERED_RECT:
|
||||
switch( n )
|
||||
{
|
||||
case 1: pt1.y -= pad->GetSize().y / 2; break; // North
|
||||
case 2: pt1.y += pad->GetSize().y / 2; break; // South
|
||||
case 3: pt1.x -= pad->GetSize().x / 2; break; // East
|
||||
case 4: pt1.x += pad->GetSize().x / 2; break; // West
|
||||
default: break; // Wicked witch
|
||||
}
|
||||
|
||||
if( !pad->GetOrientation().IsZero() )
|
||||
RotatePoint( pt1, pad->ShapePos(), pad->GetOrientation() );
|
||||
|
||||
// Thermal spokes on circular pads form an 'X' instead of a '+'
|
||||
if( pad->GetShape() == PAD_SHAPE::CIRCLE )
|
||||
RotatePoint( pt1, pad->ShapePos(), ANGLE_45 );
|
||||
|
||||
return pt1;
|
||||
|
||||
case PAD_SHAPE::CUSTOM:
|
||||
{
|
||||
switch( n )
|
||||
{
|
||||
case 1: pt1.y = INT_MIN / 2; break; // North
|
||||
case 2: pt1.y = INT_MAX / 2; break; // South
|
||||
case 3: pt1.x = INT_MIN / 2; break; // East
|
||||
case 4: pt1.x = INT_MAX / 2; break; // West
|
||||
default: break; // Wicked witch
|
||||
}
|
||||
|
||||
if( !pad->GetOrientation().IsZero() )
|
||||
RotatePoint( pt1, pad->ShapePos(), pad->GetOrientation() );
|
||||
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& padPolySet = pad->GetEffectivePolygon();
|
||||
const SHAPE_LINE_CHAIN& padOutline = padPolySet->COutline( 0 );
|
||||
SHAPE_LINE_CHAIN::INTERSECTIONS intersections;
|
||||
|
||||
padOutline.Intersect( SEG( pt0, pt1 ), intersections );
|
||||
|
||||
if( intersections.empty() )
|
||||
{
|
||||
// There should always be at least some copper outside the hole and/or
|
||||
// shapePos center
|
||||
assert( false );
|
||||
return pt0;
|
||||
}
|
||||
|
||||
return intersections[ intersections.size() - 1 ].p;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
if( n == 0 )
|
||||
|
@ -146,10 +69,9 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const
|
|||
return static_cast<const PCB_VIA*>( m_parent )->GetStart();
|
||||
|
||||
default:
|
||||
assert( false );
|
||||
UNIMPLEMENTED_FOR( m_parent->GetClass() );
|
||||
return VECTOR2I();
|
||||
}
|
||||
|
||||
return pt0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2017 CERN
|
||||
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
|
@ -36,7 +36,6 @@
|
|||
#include <zone.h>
|
||||
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/poly_grid_partition.h>
|
||||
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
@ -296,12 +295,22 @@ public:
|
|||
m_subpolyIndex( aSubpolyIndex ),
|
||||
m_layer( aLayer )
|
||||
{
|
||||
SHAPE_LINE_CHAIN outline = aParent->GetFilledPolysList( aLayer ).COutline( aSubpolyIndex );
|
||||
const SHAPE_POLY_SET& fill = aParent->GetFilledPolysList( aLayer );
|
||||
|
||||
outline.SetClosed( true );
|
||||
outline.Simplify();
|
||||
m_triangulatedSubpoly = SHAPE_POLY_SET( fill.COutline( aSubpolyIndex ) );
|
||||
m_triangulatedSubpoly.CacheTriangulation();
|
||||
|
||||
m_cachedPoly = std::make_unique<POLY_GRID_PARTITION>( outline, 16 );
|
||||
for( size_t ii = 0; ii < m_triangulatedSubpoly.TriangulatedPolyCount(); ++ii )
|
||||
{
|
||||
for( auto& tri : m_triangulatedSubpoly.TriangulatedPolygon( ii )->Triangles() )
|
||||
{
|
||||
BOX2I bbox = tri.BBox();
|
||||
const int mmin[2] = { bbox.GetX(), bbox.GetY() };
|
||||
const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
|
||||
|
||||
m_rTree.Insert( mmin, mmax, &tri );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SubpolyIndex() const
|
||||
|
@ -309,35 +318,46 @@ public:
|
|||
return m_subpolyIndex;
|
||||
}
|
||||
|
||||
bool ContainsAnchor( const CN_ANCHOR_PTR anchor ) const
|
||||
{
|
||||
return ContainsPoint( anchor->Pos(), 0 );
|
||||
}
|
||||
|
||||
bool ContainsPoint( const VECTOR2I& p, int aAccuracy = 0 ) const
|
||||
{
|
||||
return m_cachedPoly->ContainsPoint( p, aAccuracy );
|
||||
}
|
||||
|
||||
const BOX2I& BBox()
|
||||
{
|
||||
if( m_dirty )
|
||||
m_bbox = m_cachedPoly->BBox();
|
||||
|
||||
return m_bbox;
|
||||
}
|
||||
PCB_LAYER_ID GetLayer() { return m_layer; }
|
||||
|
||||
virtual int AnchorCount() const override;
|
||||
virtual const VECTOR2I GetAnchor( int n ) const override;
|
||||
|
||||
bool Collide( SHAPE* aRefShape ) const
|
||||
{
|
||||
BOX2I bbox = aRefShape->BBox();
|
||||
int min[2] = { bbox.GetX(), bbox.GetY() };
|
||||
int max[2] = { bbox.GetRight(), bbox.GetBottom() };
|
||||
bool collision = false;
|
||||
|
||||
auto visitor =
|
||||
[&]( const SHAPE* aShape ) -> bool
|
||||
{
|
||||
if( aRefShape->Collide( aShape ) )
|
||||
{
|
||||
collision = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
m_rTree.Search( min, max, visitor );
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<VECTOR2I> m_testOutlinePoints;
|
||||
std::unique_ptr<POLY_GRID_PARTITION> m_cachedPoly;
|
||||
int m_subpolyIndex;
|
||||
PCB_LAYER_ID m_layer;
|
||||
std::vector<VECTOR2I> m_testOutlinePoints;
|
||||
int m_subpolyIndex;
|
||||
PCB_LAYER_ID m_layer;
|
||||
SHAPE_POLY_SET m_triangulatedSubpoly;
|
||||
RTree<const SHAPE*, int, 2, double> m_rTree;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class CN_LIST
|
||||
{
|
||||
protected:
|
||||
|
@ -370,15 +390,8 @@ public:
|
|||
ITER begin() { return m_items.begin(); };
|
||||
ITER end() { return m_items.end(); };
|
||||
|
||||
CONST_ITER begin() const
|
||||
{
|
||||
return m_items.begin();
|
||||
}
|
||||
|
||||
CONST_ITER end() const
|
||||
{
|
||||
return m_items.end();
|
||||
}
|
||||
CONST_ITER begin() const { return m_items.begin(); }
|
||||
CONST_ITER end() const { return m_items.end(); }
|
||||
|
||||
CN_ITEM* operator[] ( int aIndex ) { return m_items[aIndex]; }
|
||||
|
||||
|
@ -403,14 +416,6 @@ public:
|
|||
SetDirty( false );
|
||||
}
|
||||
|
||||
void MarkAllAsDirty()
|
||||
{
|
||||
for( auto item : m_items )
|
||||
item->SetDirty( true );
|
||||
|
||||
SetDirty( true );
|
||||
}
|
||||
|
||||
int Size() const
|
||||
{
|
||||
return m_items.size();
|
||||
|
@ -427,10 +432,9 @@ public:
|
|||
const std::vector<CN_ITEM*> Add( ZONE* zone, PCB_LAYER_ID aLayer );
|
||||
|
||||
private:
|
||||
bool m_dirty;
|
||||
bool m_hasInvalid;
|
||||
|
||||
CN_RTREE<CN_ITEM*> m_index;
|
||||
bool m_dirty;
|
||||
bool m_hasInvalid;
|
||||
CN_RTREE<CN_ITEM*> m_index;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ set( KIMATH_SRCS
|
|||
geometry/test_shape_poly_set_collision.cpp
|
||||
geometry/test_shape_poly_set_distance.cpp
|
||||
geometry/test_shape_poly_set_iterator.cpp
|
||||
geometry/test_poly_grid_partition.cpp
|
||||
geometry/test_shape_line_chain.cpp
|
||||
|
||||
math/test_vector2.cpp
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 CERN
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
|
||||
#include <geometry/poly_grid_partition.h>
|
||||
|
||||
struct PGPartitionFixture
|
||||
{
|
||||
SHAPE_POLY_SET testPolys[2];
|
||||
|
||||
std::vector<VECTOR2I> testPoints;
|
||||
|
||||
PGPartitionFixture()
|
||||
{
|
||||
|
||||
testPoints.push_back( VECTOR2I( -2794000, 47830000 ) );
|
||||
testPoints.push_back( VECTOR2I( -3730000, 47820000 ) );
|
||||
|
||||
// auto-generated code. don't complain about formatting...
|
||||
{ auto tmp = SHAPE_LINE_CHAIN( { VECTOR2I( -1902094, 47420002), VECTOR2I( -1855601, 47473658), VECTOR2I( -1845000, 47513474), VECTOR2I( -1845000, 47517499), VECTOR2I( -1843938, 47523201), VECTOR2I( -1826178, 47618564), VECTOR2I( -1826177, 47618567), VECTOR2I( -1824048, 47629998), VECTOR2I( -1764001, 47727412), VECTOR2I( -1754742, 47734452), VECTOR2I( -1754741, 47734454), VECTOR2I( -1707035, 47770730), VECTOR2I( -1672912, 47796678), VECTOR2I( -1562995, 47828508), VECTOR2I( -1555663, 47828866), VECTOR2I( -1555660, 47828867), VECTOR2I( -1546053, 47829336), VECTOR2I( -1532500, 47829999), VECTOR2I( -1455410, 47829999), VECTOR2I( -1173301, 47830000), VECTOR2I( -1167501, 47830000), VECTOR2I( -1095939, 47816672), VECTOR2I( -1006088, 47833695), VECTOR2I( -921000, 47886876), VECTOR2I( -885528, 47920101), VECTOR2I( -257059, 48792973), VECTOR2I( -105269, 49003793), VECTOR2I( -86131, 49009997), VECTOR2I( 458321, 49186489), VECTOR2I( 524305, 49236457), VECTOR2I( 782412, 49623618), VECTOR2I( 803006, 49681564), VECTOR2I( 899432, 50694036), VECTOR2I( 900000, 50705982), VECTOR2I( 900000, 51374000), VECTOR2I( 879998, 51442121), VECTOR2I( 826342, 51488614), VECTOR2I( 774000, 51500000), VECTOR2I( -174000, 51500000), VECTOR2I( -242121, 51479998), VECTOR2I( -288614, 51426342), VECTOR2I( -300000, 51374000), VECTOR2I( -300000, 50500000), VECTOR2I( -1400000, 50500000), VECTOR2I( -1407434, 50517346), VECTOR2I( -1667272, 51123634), VECTOR2I( -1712491, 51178368), VECTOR2I( -1783084, 51200000), VECTOR2I( -4974000, 51200000), VECTOR2I( -5042121, 51179998), VECTOR2I( -5088614, 51126342), VECTOR2I( -5100000, 51074000), VECTOR2I( -5100000, 47526000), VECTOR2I( -5079998, 47457879), VECTOR2I( -5026342, 47411386), VECTOR2I( -4974000, 47400000), VECTOR2I( -1970215, 47400000)}, true );;
|
||||
testPolys[0].AddOutline(tmp); testPolys[0].Unfracture( SHAPE_POLY_SET::PM_FAST ); }
|
||||
|
||||
|
||||
{ auto tmp = SHAPE_LINE_CHAIN( { VECTOR2I( -1669357, 47419152), VECTOR2I( -921001, 47886875), VECTOR2I( -885528, 47920101), VECTOR2I( -257059, 48792973), VECTOR2I( -105269, 49003793), VECTOR2I( 478113, 49192905), VECTOR2I( 517969, 49214375), VECTOR2I( 716789, 49373432), VECTOR2I( 760315, 49441261), VECTOR2I( 792698, 49570792), VECTOR2I( 789815, 49641728), VECTOR2I( 768344, 49676295), VECTOR2I( 768537, 49676413), VECTOR2I( 760684, 49689316), VECTOR2I( 750000, 49700000), VECTOR2I( 745420, 49714395), VECTOR2I( 427935, 50712204), VECTOR2I( 388220, 50771053), VECTOR2I( 307866, 50800000), VECTOR2I( 234899, 50800000), VECTOR2I( 170073, 50782044), VECTOR2I( -285313, 50508812), VECTOR2I( -285314, 50508812), VECTOR2I( -300000, 50500000), VECTOR2I( -1400000, 50500000), VECTOR2I( -1407434, 50517346), VECTOR2I( -1667272, 51123634), VECTOR2I( -1712491, 51178368), VECTOR2I( -1783084, 51200000), VECTOR2I( -4974000, 51200000), VECTOR2I( -5042121, 51179998), VECTOR2I( -5088614, 51126342), VECTOR2I( -5100000, 51074000), VECTOR2I( -5100000, 47526000), VECTOR2I( -5079998, 47457879), VECTOR2I( -5026342, 47411386), VECTOR2I( -4974000, 47400000), VECTOR2I( -1736137, 47400000)}, true );;
|
||||
testPolys[1].AddOutline(tmp); testPolys[1].Unfracture( SHAPE_POLY_SET::PM_FAST ); }
|
||||
}
|
||||
|
||||
~PGPartitionFixture()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE( PGPartitionTest, PGPartitionFixture )
|
||||
|
||||
BOOST_AUTO_TEST_CASE( PointInside )
|
||||
{
|
||||
for( auto p : testPoints )
|
||||
{
|
||||
for ( auto& poly : testPolys )
|
||||
{
|
||||
bool fallback_in = poly.Contains( p );
|
||||
poly.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
POLY_GRID_PARTITION part( poly.COutline(0), 16 );
|
||||
bool pgp_in = part.ContainsPoint( p );
|
||||
|
||||
// compare vanilla point-in-polygon with the grid partitioning.
|
||||
BOOST_CHECK_EQUAL( fallback_in, pgp_in );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue