diff --git a/libs/kimath/CMakeLists.txt b/libs/kimath/CMakeLists.txt index 24dfbc7e42..ea4e12d043 100644 --- a/libs/kimath/CMakeLists.txt +++ b/libs/kimath/CMakeLists.txt @@ -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 diff --git a/libs/kimath/include/geometry/poly_grid_partition.h b/libs/kimath/include/geometry/poly_grid_partition.h deleted file mode 100644 index eec25e0dff..0000000000 --- a/libs/kimath/include/geometry/poly_grid_partition.h +++ /dev/null @@ -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 - * - * 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 -#include -#include -#include -#include - -#include -#include -#include -#include - -/** - * 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; - - template - inline void hash_combine( std::size_t& seed, const T& v ) - { - std::hash 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 m_flags; - std::vector m_grid; -}; - -#endif diff --git a/libs/kimath/include/geometry/shape_poly_set.h b/libs/kimath/include/geometry/shape_poly_set.h index aa2377eb4a..fecf0b659e 100644 --- a/libs/kimath/include/geometry/shape_poly_set.h +++ b/libs/kimath/include/geometry/shape_poly_set.h @@ -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& Triangles() - { - return m_triangles; - } + std::deque& Triangles() { return m_triangles; } + const std::deque& 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; } diff --git a/libs/kimath/src/geometry/poly_grid_partition.cpp b/libs/kimath/src/geometry/poly_grid_partition.cpp deleted file mode 100644 index 62a8f0ac57..0000000000 --- a/libs/kimath/src/geometry/poly_grid_partition.cpp +++ /dev/null @@ -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 - * - * 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 -#include - -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 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 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; -} \ No newline at end of file diff --git a/libs/kimath/src/geometry/shape_poly_set.cpp b/libs/kimath/src/geometry/shape_poly_set.cpp index 34d9f7da55..079b588c3f 100644 --- a/libs/kimath/src/geometry/shape_poly_set.cpp +++ b/libs/kimath/src/geometry/shape_poly_set.cpp @@ -2464,7 +2464,7 @@ size_t SHAPE_POLY_SET::GetIndexableSubshapeCount() const } -void SHAPE_POLY_SET:: GetIndexableSubshapes( std::vector& aSubshapes ) +void SHAPE_POLY_SET::GetIndexableSubshapes( std::vector& aSubshapes ) { aSubshapes.reserve( GetIndexableSubshapeCount() ); diff --git a/pcbnew/connectivity/connectivity_algo.cpp b/pcbnew/connectivity/connectivity_algo.cpp index c737954566..aabe4526e3 100644 --- a/pcbnew/connectivity/connectivity_algo.cpp +++ b/pcbnew/connectivity/connectivity_algo.cpp @@ -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 * @@ -604,7 +604,7 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE* aZone, PCB_LAYER_ID void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector& 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( 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( aZoneLayerA->Parent() ); - const ZONE* zoneB = static_cast( 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( 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 ); } } diff --git a/pcbnew/connectivity/connectivity_algo.h b/pcbnew/connectivity/connectivity_algo.h index 3773e9ad50..d1cb2268ae 100644 --- a/pcbnew/connectivity/connectivity_algo.h +++ b/pcbnew/connectivity/connectivity_algo.h @@ -36,7 +36,6 @@ #include #include -#include #include #include diff --git a/pcbnew/connectivity/connectivity_items.cpp b/pcbnew/connectivity/connectivity_items.cpp index fff732e756..82b7678b0e 100644 --- a/pcbnew/connectivity/connectivity_items.cpp +++ b/pcbnew/connectivity/connectivity_items.cpp @@ -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( m_parent ); + return static_cast( 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& 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( m_parent )->GetStart(); default: - assert( false ); + UNIMPLEMENTED_FOR( m_parent->GetClass() ); + return VECTOR2I(); } - - return pt0; } diff --git a/pcbnew/connectivity/connectivity_items.h b/pcbnew/connectivity/connectivity_items.h index 79845d14a4..44faffa10c 100644 --- a/pcbnew/connectivity/connectivity_items.h +++ b/pcbnew/connectivity/connectivity_items.h @@ -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 * @author Tomasz Wlostowski @@ -36,7 +36,6 @@ #include #include -#include #include #include @@ -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( 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 m_testOutlinePoints; - std::unique_ptr m_cachedPoly; - int m_subpolyIndex; - PCB_LAYER_ID m_layer; + std::vector m_testOutlinePoints; + int m_subpolyIndex; + PCB_LAYER_ID m_layer; + SHAPE_POLY_SET m_triangulatedSubpoly; + RTree 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 Add( ZONE* zone, PCB_LAYER_ID aLayer ); private: - bool m_dirty; - bool m_hasInvalid; - - CN_RTREE m_index; + bool m_dirty; + bool m_hasInvalid; + CN_RTREE m_index; }; diff --git a/qa/libs/kimath/CMakeLists.txt b/qa/libs/kimath/CMakeLists.txt index 6f1dd1848e..6c9cbf9ea3 100644 --- a/qa/libs/kimath/CMakeLists.txt +++ b/qa/libs/kimath/CMakeLists.txt @@ -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 diff --git a/qa/libs/kimath/geometry/test_poly_grid_partition.cpp b/qa/libs/kimath/geometry/test_poly_grid_partition.cpp deleted file mode 100644 index ecca171028..0000000000 --- a/qa/libs/kimath/geometry/test_poly_grid_partition.cpp +++ /dev/null @@ -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 - -#include -#include - -#include - -struct PGPartitionFixture -{ - SHAPE_POLY_SET testPolys[2]; - - std::vector 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()