7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-17 00:29:06 +00:00

pcbnew: Optimized zone filling algorithm.

This commit is contained in:
Tomasz Włostowski 2017-11-23 17:20:27 +01:00
parent 8b68a1736a
commit 316ddadec1
46 changed files with 3998 additions and 2754 deletions

View File

@ -478,6 +478,7 @@ include( CheckFindPackageResult )
find_package( OpenMP )
if( OPENMP_FOUND )
message( "FOUND OPENMP" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}" )
add_definitions( -DUSE_OPENMP )

View File

@ -179,6 +179,7 @@ set( COMMON_WIDGET_SRCS
widgets/indicator_icon.cpp
widgets/text_ctrl_eval.cpp
widgets/unit_binder.cpp
widgets/progress_reporter.cpp
)
set( COMMON_PAGE_LAYOUT_SRCS
@ -273,6 +274,7 @@ set( COMMON_SRCS
kiway_player.cpp
lib_table_base.cpp
lockfile.cpp
md5_hash.cpp
msgpanel.cpp
netlist_keywords.cpp
observable.cpp

View File

@ -776,9 +776,52 @@ void OPENGL_GAL::DrawPolygon( const VECTOR2D aPointList[], int aListSize )
drawPolygon( points.get(), aListSize );
}
void OPENGL_GAL::drawTriangulatedPolyset( const SHAPE_POLY_SET& aPolySet )
{
currentManager->Shader( SHADER_NONE );
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
if ( isFillEnabled )
{
for( int j = 0; j < aPolySet.OutlineCount(); ++j )
{
auto triPoly = aPolySet.TriangulatedPolygon( j );
for ( int i = 0; i < triPoly->m_triangleCount; i++ )
{
VECTOR2I a, b, c;
triPoly->GetTriangle( i ,a,b,c);
currentManager->Vertex( a.x, a.y, layerDepth );
currentManager->Vertex( b.x, b.y, layerDepth );
currentManager->Vertex( c.x, c.y, layerDepth );
}
}
}
if( isStrokeEnabled )
{
for( int j = 0; j < aPolySet.OutlineCount(); ++j )
{
const auto& poly = aPolySet.Polygon( j );
for( const auto& lc : poly )
{
DrawPolyline( lc );
}
}
}
}
void OPENGL_GAL::DrawPolygon( const SHAPE_POLY_SET& aPolySet )
{
if ( aPolySet.IsTriangulationUpToDate() )
{
drawTriangulatedPolyset( aPolySet );
return;
}
for( int j = 0; j < aPolySet.OutlineCount(); ++j )
{
const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( j );
@ -1470,7 +1513,6 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa
Restore();
}
void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount )
{
currentManager->Shader( SHADER_NONE );

File diff suppressed because it is too large Load Diff

250
common/md5_hash.cpp Normal file
View File

@ -0,0 +1,250 @@
// Code by: B-Con (http://b-con.us)
// Released under the GNU GPL
// MD5 Hash Digest implementation (little endian byte order)
#include <cstring>
#include <cstdio>
#include <md5_hash.h>
// DBL_INT_ADD treats two unsigned ints a and b as one 64-bit integer and adds c to it
#define DBL_INT_ADD(a,b,c) if (a > 0xffffffff - c) ++b; a += c;
#define ROTLEFT(a,b) ((a << b) | (a >> (32-b)))
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x ^ y ^ z)
#define I(x,y,z) (y ^ (x | ~z))
#define FF(a,b,c,d,m,s,t) { a += F(b,c,d) + m + t; \
a = b + ROTLEFT(a,s); }
#define GG(a,b,c,d,m,s,t) { a += G(b,c,d) + m + t; \
a = b + ROTLEFT(a,s); }
#define HH(a,b,c,d,m,s,t) { a += H(b,c,d) + m + t; \
a = b + ROTLEFT(a,s); }
#define II(a,b,c,d,m,s,t) { a += I(b,c,d) + m + t; \
a = b + ROTLEFT(a,s); }
MD5_HASH::MD5_HASH()
{
Init();
}
MD5_HASH::MD5_HASH( const MD5_HASH& aOther )
{
m_valid = aOther.m_valid;
m_ctx = aOther.m_ctx;
memcpy( m_hash, aOther.m_hash, 16 );
}
MD5_HASH::~MD5_HASH()
{
}
MD5_HASH& MD5_HASH::operator=( const MD5_HASH& aOther )
{
m_valid = aOther.m_valid;
m_ctx = aOther.m_ctx;
memcpy( m_hash, aOther.m_hash, 16 );
return *this;
}
void MD5_HASH::Init()
{
//printf("%p init\n", this);
m_valid = false;
md5_init(&m_ctx);
}
void MD5_HASH::Hash ( uint8_t *data, uint32_t length )
{
md5_update(&m_ctx, data, length);
}
void MD5_HASH::Hash ( int value )
{
md5_update(&m_ctx, (uint8_t*) &value, sizeof(int) );
}
void MD5_HASH::Finalize()
{
//printf("%p final\n", this);
md5_final(&m_ctx, m_hash);
m_valid = true;
}
bool MD5_HASH::operator==( const MD5_HASH& aOther ) const
{
return ( memcmp( m_hash, aOther.m_hash, 16 ) == 0 );
}
bool MD5_HASH::operator!=( const MD5_HASH& aOther ) const
{
return ( memcmp( m_hash, aOther.m_hash, 16 ) != 0 );
}
void MD5_HASH::md5_transform(MD5_CTX *ctx, uint8_t data[])
{
uint32_t a,b,c,d,m[16],i,j;
// MD5 specifies big endian byte order, but this implementation assumes a little
// endian byte order CPU. Reverse all the bytes upon input, and re-reverse them
// on output (in md5_final()).
for (i=0,j=0; i < 16; ++i, j += 4)
m[i] = (data[j]) + (data[j+1] << 8) + (data[j+2] << 16) + (data[j+3] << 24);
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
FF(a,b,c,d,m[0], 7,0xd76aa478);
FF(d,a,b,c,m[1], 12,0xe8c7b756);
FF(c,d,a,b,m[2], 17,0x242070db);
FF(b,c,d,a,m[3], 22,0xc1bdceee);
FF(a,b,c,d,m[4], 7,0xf57c0faf);
FF(d,a,b,c,m[5], 12,0x4787c62a);
FF(c,d,a,b,m[6], 17,0xa8304613);
FF(b,c,d,a,m[7], 22,0xfd469501);
FF(a,b,c,d,m[8], 7,0x698098d8);
FF(d,a,b,c,m[9], 12,0x8b44f7af);
FF(c,d,a,b,m[10],17,0xffff5bb1);
FF(b,c,d,a,m[11],22,0x895cd7be);
FF(a,b,c,d,m[12], 7,0x6b901122);
FF(d,a,b,c,m[13],12,0xfd987193);
FF(c,d,a,b,m[14],17,0xa679438e);
FF(b,c,d,a,m[15],22,0x49b40821);
GG(a,b,c,d,m[1], 5,0xf61e2562);
GG(d,a,b,c,m[6], 9,0xc040b340);
GG(c,d,a,b,m[11],14,0x265e5a51);
GG(b,c,d,a,m[0], 20,0xe9b6c7aa);
GG(a,b,c,d,m[5], 5,0xd62f105d);
GG(d,a,b,c,m[10], 9,0x02441453);
GG(c,d,a,b,m[15],14,0xd8a1e681);
GG(b,c,d,a,m[4], 20,0xe7d3fbc8);
GG(a,b,c,d,m[9], 5,0x21e1cde6);
GG(d,a,b,c,m[14], 9,0xc33707d6);
GG(c,d,a,b,m[3], 14,0xf4d50d87);
GG(b,c,d,a,m[8], 20,0x455a14ed);
GG(a,b,c,d,m[13], 5,0xa9e3e905);
GG(d,a,b,c,m[2], 9,0xfcefa3f8);
GG(c,d,a,b,m[7], 14,0x676f02d9);
GG(b,c,d,a,m[12],20,0x8d2a4c8a);
HH(a,b,c,d,m[5], 4,0xfffa3942);
HH(d,a,b,c,m[8], 11,0x8771f681);
HH(c,d,a,b,m[11],16,0x6d9d6122);
HH(b,c,d,a,m[14],23,0xfde5380c);
HH(a,b,c,d,m[1], 4,0xa4beea44);
HH(d,a,b,c,m[4], 11,0x4bdecfa9);
HH(c,d,a,b,m[7], 16,0xf6bb4b60);
HH(b,c,d,a,m[10],23,0xbebfbc70);
HH(a,b,c,d,m[13], 4,0x289b7ec6);
HH(d,a,b,c,m[0], 11,0xeaa127fa);
HH(c,d,a,b,m[3], 16,0xd4ef3085);
HH(b,c,d,a,m[6], 23,0x04881d05);
HH(a,b,c,d,m[9], 4,0xd9d4d039);
HH(d,a,b,c,m[12],11,0xe6db99e5);
HH(c,d,a,b,m[15],16,0x1fa27cf8);
HH(b,c,d,a,m[2], 23,0xc4ac5665);
II(a,b,c,d,m[0], 6,0xf4292244);
II(d,a,b,c,m[7], 10,0x432aff97);
II(c,d,a,b,m[14],15,0xab9423a7);
II(b,c,d,a,m[5], 21,0xfc93a039);
II(a,b,c,d,m[12], 6,0x655b59c3);
II(d,a,b,c,m[3], 10,0x8f0ccc92);
II(c,d,a,b,m[10],15,0xffeff47d);
II(b,c,d,a,m[1], 21,0x85845dd1);
II(a,b,c,d,m[8], 6,0x6fa87e4f);
II(d,a,b,c,m[15],10,0xfe2ce6e0);
II(c,d,a,b,m[6], 15,0xa3014314);
II(b,c,d,a,m[13],21,0x4e0811a1);
II(a,b,c,d,m[4], 6,0xf7537e82);
II(d,a,b,c,m[11],10,0xbd3af235);
II(c,d,a,b,m[2], 15,0x2ad7d2bb);
II(b,c,d,a,m[9], 21,0xeb86d391);
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
}
void MD5_HASH::md5_init(MD5_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen[0] = 0;
ctx->bitlen[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
}
void MD5_HASH::md5_update(MD5_CTX *ctx, uint8_t data[], uint32_t len)
{
uint32_t t,i;
for (i=0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
md5_transform(ctx,ctx->data);
DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],512);
ctx->datalen = 0;
}
}
}
void MD5_HASH::md5_final(MD5_CTX *ctx, uint8_t hash[])
{
uint32_t i;
i = ctx->datalen;
// Pad whatever data is left in the buffer.
if (ctx->datalen < 56) {
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
}
else if (ctx->datalen >= 56) {
ctx->data[i++] = 0x80;
while (i < 64)
ctx->data[i++] = 0x00;
md5_transform(ctx,ctx->data);
memset(ctx->data,0,56);
}
// Append to the padding the total message's length in bits and transform.
DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],8 * ctx->datalen);
ctx->data[56] = ctx->bitlen[0];
ctx->data[57] = ctx->bitlen[0] >> 8;
ctx->data[58] = ctx->bitlen[0] >> 16;
ctx->data[59] = ctx->bitlen[0] >> 24;
ctx->data[60] = ctx->bitlen[1];
ctx->data[61] = ctx->bitlen[1] >> 8;
ctx->data[62] = ctx->bitlen[1] >> 16;
ctx->data[63] = ctx->bitlen[1] >> 24;
md5_transform(ctx,ctx->data);
// Since this implementation uses little endian byte ordering and MD uses big endian,
// reverse all the bytes when copying the final state to the output hash.
for (i=0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (i*8)) & 0x000000ff;
hash[i+4] = (ctx->state[1] >> (i*8)) & 0x000000ff;
hash[i+8] = (ctx->state[2] >> (i*8)) & 0x000000ff;
hash[i+12] = (ctx->state[3] >> (i*8)) & 0x000000ff;
}
}

View File

@ -0,0 +1,102 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 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 <widgets/progress_reporter.h>
#include <thread>
PROGRESS_REPORTER::PROGRESS_REPORTER( int aNumPhases ) :
m_phase( 0 ),
m_progress( 0 ),
m_maxProgress( 1 ),
m_numPhases( aNumPhases )
{
};
void PROGRESS_REPORTER::BeginPhase( int aPhase )
{
std::lock_guard<std::mutex> guard( m_lock );
m_phase = aPhase;
m_progress = 0;
updateUI();
}
void PROGRESS_REPORTER::AdvancePhase( )
{
std::lock_guard<std::mutex> guard( m_lock );
m_phase++;
m_progress = 0;
updateUI();
}
void PROGRESS_REPORTER::Report( const wxString& aMessage )
{
std::lock_guard<std::mutex> guard( m_lock );
m_message = aMessage;
updateUI();
}
void PROGRESS_REPORTER::SetMaxProgress ( int aMaxProgress )
{
std::lock_guard<std::mutex> guard( m_lock );
m_maxProgress = aMaxProgress;
updateUI();
}
void PROGRESS_REPORTER::AdvanceProgress( )
{
std::lock_guard<std::mutex> guard( m_lock );
m_progress++;
updateUI();
}
int PROGRESS_REPORTER::currentProgress() const
{
double current = (1.0 / (double)m_numPhases) * ( (double) m_phase + ( (double) m_progress / (double) m_maxProgress ) );
return (int)(current * 1000);
}
WX_PROGRESS_REPORTER::WX_PROGRESS_REPORTER( wxWindow* aParent,
const wxString& aTitle,
int aNumPhases ) :
PROGRESS_REPORTER( aNumPhases ),
wxProgressDialog( aTitle, wxT( "" ), 1, aParent, wxPD_AUTO_HIDE | wxPD_CAN_ABORT |
wxPD_APP_MODAL | wxPD_ELAPSED_TIME )
{
}
WX_PROGRESS_REPORTER::~WX_PROGRESS_REPORTER()
{
Destroy();
}
void WX_PROGRESS_REPORTER::updateUI()
{
int cur = currentProgress();
SetRange( 1000 );
Update( cur, m_message );
}

View File

@ -387,6 +387,12 @@ private:
*/
void drawPolygon( GLdouble* aPoints, int aPointCount );
/**
* @brief Draws a set of polygons with a cached triangulation. Way faster than drawPolygon.
*/
void drawTriangulatedPolyset( const SHAPE_POLY_SET& aPoly );
/**
* @brief Draws a single character using bitmap font.
* Its main purpose is to be used in BitmapText() function.

View File

@ -102,6 +102,16 @@ public:
return *this;
}
bool operator==( const SEG& aSeg ) const
{
return (A == aSeg.A && B == aSeg.B) ;
}
bool operator!=( const SEG& aSeg ) const
{
return (A != aSeg.A || B != aSeg.B);
}
/**
* Function LineProject()
*

View File

@ -33,6 +33,8 @@
#include "clipper.hpp"
#include <md5_hash.h>
/**
* Class SHAPE_POLY_SET
@ -57,6 +59,42 @@ class SHAPE_POLY_SET : public SHAPE
///> the remaining (if any), are the holes
typedef std::vector<SHAPE_LINE_CHAIN> POLYGON;
struct TRIANGULATED_POLYGON
{
~TRIANGULATED_POLYGON();
struct TRI
{
TRI(){};
int a, b, c;
};
void Clear();
void AllocateVertices( int aSize );
void AllocateTriangles ( int aSize );
void GetTriangle( int index, VECTOR2I& a, VECTOR2I& b, VECTOR2I& c ) const
{
auto tri = &m_triangles[ index ];
a = m_vertices[ tri->a ];
b = m_vertices[ tri->b ];
c = m_vertices[ tri->c ];
}
int AddVertex( const VECTOR2I& aP )
{
m_vertices[ m_vertexCount ] = aP;
return (m_vertexCount++);
}
TRI* m_triangles = nullptr;
VECTOR2I* m_vertices = nullptr;
int m_vertexCount = 0;
int m_triangleCount = 0;
};
/**
* Struct VERTEX_INDEX
*
@ -538,6 +576,17 @@ class SHAPE_POLY_SET : public SHAPE
return m_polys[aIndex];
}
const POLYGON& Polygon( int aIndex ) const
{
return m_polys[aIndex];
}
const TRIANGULATED_POLYGON* TriangulatedPolygon( int aIndex ) const
{
return m_triangulatedPolys[aIndex];
}
const SHAPE_LINE_CHAIN& COutline( int aIndex ) const
{
return m_polys[aIndex][0];
@ -761,6 +810,8 @@ class SHAPE_POLY_SET : public SHAPE
///> For aFastMode meaning, see function booleanOp
void Fracture( POLYGON_MODE aFastMode );
void Unfracture( POLYGON_MODE aFastMode );
///> Returns true if the polygon set has any holes.
bool HasHoles() const;
@ -990,6 +1041,7 @@ class SHAPE_POLY_SET : public SHAPE
void fractureSingle( POLYGON& paths );
void unfractureSingle ( POLYGON& path );
void importTree( ClipperLib::PolyTree* tree );
/** Function booleanOp
@ -1039,6 +1091,8 @@ class SHAPE_POLY_SET : public SHAPE
FILLETED
};
/**
* Function chamferFilletPolygon
* Returns the camfered or filleted version of the aIndex-th polygon in the set, depending
@ -1059,6 +1113,21 @@ class SHAPE_POLY_SET : public SHAPE
typedef std::vector<POLYGON> POLYSET;
POLYSET m_polys;
public:
void CacheTriangulation();
bool IsTriangulationUpToDate() const;
private:
void triangulateSingle( const POLYGON& aPoly, SHAPE_POLY_SET::TRIANGULATED_POLYGON& aResult );
MD5_HASH checksum() const;
std::vector<TRIANGULATED_POLYGON*> m_triangulatedPolys;
bool m_triangulationValid = false;
MD5_HASH m_hash;
};
#endif

50
include/md5_hash.h Normal file
View File

@ -0,0 +1,50 @@
// Code by: B-Con (http://b-con.us)
// Released under the GNU GPL
// MD5 Hash Digest implementation (little endian byte order)
#ifndef __MD5_HASH_H
#define __MD5_HASH_H
#include <cstdint>
class MD5_HASH
{
public:
MD5_HASH();
MD5_HASH( const MD5_HASH& aOther );
~MD5_HASH();
void Init();
void Hash ( uint8_t *data, uint32_t length );
void Hash ( int value );
void Finalize();
bool IsValid() const { return m_valid; };
void SetValid( bool aValid ) { m_valid = aValid; }
MD5_HASH& operator=( const MD5_HASH& aOther );
bool operator==( const MD5_HASH& aOther ) const;
bool operator!=( const MD5_HASH& aOther ) const;
private:
struct MD5_CTX {
uint8_t data[64];
uint32_t datalen;
uint32_t bitlen[2];
uint32_t state[4];
};
void md5_transform(MD5_CTX *ctx, uint8_t data[]);
void md5_init(MD5_CTX *ctx);
void md5_update(MD5_CTX *ctx, uint8_t data[], uint32_t len);
void md5_final(MD5_CTX *ctx, uint8_t hash[]);
bool m_valid;
MD5_CTX m_ctx;
uint8_t m_hash[16];
};
#endif

View File

@ -0,0 +1,69 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 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
*/
#ifndef __PROGRESS_REPORTER
#define __PROGRESS_REPORTER
#include <mutex>
#include <wx/progdlg.h>
class PROGRESS_REPORTER
{
public:
PROGRESS_REPORTER( int aNumPhases );
PROGRESS_REPORTER( const PROGRESS_REPORTER& ) = delete;
void BeginPhase( int aPhase );
void AdvancePhase( );
void Report ( const wxString& aMessage );
void SetMaxProgress ( int aMaxProgress );
void AdvanceProgress( );
protected:
int currentProgress() const;
virtual void updateUI() = 0;
wxString m_message;
int m_phase, m_numPhases;
int m_progress, m_maxProgress;
std::mutex m_lock;
};
class WX_PROGRESS_REPORTER : public PROGRESS_REPORTER, public wxProgressDialog
{
public:
WX_PROGRESS_REPORTER( wxWindow *aParent, const wxString &aTitle, int aNumPhases );
~WX_PROGRESS_REPORTER();
private:
virtual void updateUI() override;
};
#endif

View File

@ -315,6 +315,7 @@ set( PCBNEW_CLASS_SRCS
tools/tool_event_utils.cpp
tools/size_menu.cpp
tools/selection.cpp
tools/zone_filler_tool.cpp
footprint_preview_panel.cpp
)

View File

@ -1312,3 +1312,8 @@ void ZONE_CONTAINER::SwapData( BOARD_ITEM* aImage )
std::swap( *((ZONE_CONTAINER*) this), *((ZONE_CONTAINER*) aImage) );
}
void ZONE_CONTAINER::CacheTriangulation()
{
m_FilledPolysList.CacheTriangulation();
}

View File

@ -170,11 +170,11 @@ public:
int GetClearance( BOARD_CONNECTED_ITEM* aItem = NULL ) const override;
/**
* Function TestForCopperIslandAndRemoveInsulatedIslands
* Function RemoveInsulatedCopperIslands
* Remove insulated copper islands found in m_FilledPolysList.
* @param aPcb = the board to analyze
*/
void TestForCopperIslandAndRemoveInsulatedIslands( BOARD* aPcb );
void RemoveInsulatedCopperIslands( BOARD* aPcb );
/**
* Function IsOnCopperLayer
@ -329,7 +329,7 @@ public:
bool BuildFilledSolidAreasPolygons( BOARD* aPcb, SHAPE_POLY_SET* aOutlineBuffer = NULL );
/**
* Function AddClearanceAreasPolygonsToPolysList
* Function ComputeRawFilledAreas
* Add non copper areas polygons (pads and tracks with clearance)
* to a filled copper area
* used in BuildFilledSolidAreasPolygons when calculating filled areas in a zone
@ -340,8 +340,7 @@ public:
* @param aPcb: the current board
* _NG version uses SHAPE_POLY_SET instead of Boost.Polygon
*/
void AddClearanceAreasPolygonsToPolysList( BOARD* aPcb );
void AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb );
void ComputeRawFilledAreas( BOARD* aPcb );
/**
@ -602,6 +601,8 @@ public:
return m_FilledPolysList;
}
void CacheTriangulation();
/**
* Function AddFilledPolysList
* sets the list of filled polygons.
@ -728,7 +729,6 @@ public:
const std::vector<SEG>& GetHatchLines() const { return m_HatchLines; }
#if defined(DEBUG)
virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
@ -810,6 +810,8 @@ private:
int m_hatchPitch; // for DIAGONAL_EDGE, distance between 2 hatch lines
std::vector<SEG> m_HatchLines; // hatch lines
std::vector<int> m_insulatedIslands;
/**
* Union to handle conversion between references to wxPoint and to VECTOR2I.
*

View File

@ -23,6 +23,10 @@
*/
#include <connectivity_algo.h>
#include <widgets/progress_reporter.h>
#include <thread>
#include <mutex>
#ifdef PROFILE
#include <profile.h>
@ -289,9 +293,11 @@ bool CN_CONNECTIVITY_ALGO::Add( BOARD_ITEM* aItem )
return true;
}
void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
{
std::mutex cnListLock;
//PROF_COUNTER cnt("search");
int totalDirtyCount = 0;
if( m_lastSearchWithZones != aIncludeZones )
@ -304,7 +310,7 @@ void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
m_lastSearchWithZones = aIncludeZones;
auto checkForConnection = [] ( const CN_ANCHOR_PTR point, CN_ITEM* aRefItem, int aMaxDist = 0 )
auto checkForConnection = [ &cnListLock ] ( const CN_ANCHOR_PTR point, CN_ITEM* aRefItem, int aMaxDist = 0 )
{
const auto parent = aRefItem->Parent();
@ -331,7 +337,10 @@ void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
case PCB_VIA_T:
if( parent->HitTest( wxPoint( point->Pos().x, point->Pos().y ) ) )
{
std::lock_guard<std::mutex> lock( cnListLock );
CN_ITEM::Connect( aRefItem, point->Item() );
}
break;
@ -344,7 +353,10 @@ void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
if( d_start.EuclideanNorm() < aMaxDist
|| d_end.EuclideanNorm() < aMaxDist )
{
std::lock_guard<std::mutex> lock( cnListLock );
CN_ITEM::Connect( aRefItem, point->Item() );
}
break;
}
@ -363,6 +375,7 @@ void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
if( zoneItem->ContainsAnchor( point ) )
{
std::lock_guard<std::mutex> lock( cnListLock );
CN_ITEM::Connect( zoneItem, point->Item() );
}
@ -374,7 +387,7 @@ void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
}
};
auto checkInterZoneConnection = [] ( CN_ZONE* testedZone, CN_ZONE* aRefZone )
auto checkInterZoneConnection = [ &cnListLock ] ( CN_ZONE* testedZone, CN_ZONE* aRefZone )
{
const auto parentZone = static_cast<const ZONE_CONTAINER*>( aRefZone->Parent() );
@ -399,6 +412,8 @@ void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
{
if( testedZone->ContainsPoint( outline.CPoint( i ) ) )
{
std::lock_guard<std::mutex> lock( cnListLock );
CN_ITEM::Connect( aRefZone, testedZone );
return;
}
@ -412,6 +427,8 @@ void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
{
if( aRefZone->ContainsPoint( outline2.CPoint( i ) ) )
{
std::lock_guard<std::mutex> lock( cnListLock );
CN_ITEM::Connect( aRefZone, testedZone );
return;
}
@ -496,8 +513,19 @@ void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
if( aIncludeZones )
{
for( auto& item : m_zoneList )
int cnt = 0;
if( m_progressReporter )
{
m_progressReporter->SetMaxProgress( m_zoneList.Size() );
}
#ifdef USE_OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for(int i = 0; i < m_zoneList.Size(); i++ )
{
auto item = m_zoneList[i];
auto zoneItem = static_cast<CN_ZONE *> (item);
auto searchZones = std::bind( checkForConnection, _1, zoneItem );
@ -509,6 +537,16 @@ void CN_CONNECTIVITY_ALGO::searchConnections( bool aIncludeZones )
m_padList.FindNearby( zoneItem->BBox(), searchZones );
m_zoneList.FindNearbyZones( zoneItem->BBox(), std::bind( checkInterZoneConnection, _1, zoneItem ) );
}
{
std::lock_guard<std::mutex> lock( cnListLock );
cnt++;
if (m_progressReporter)
{
m_progressReporter->AdvanceProgress();
}
}
}
m_zoneList.ClearDirtyFlags();
@ -589,6 +627,7 @@ const CN_CONNECTIVITY_ALGO::CLUSTERS CN_CONNECTIVITY_ALGO::SearchClusters( CLUST
CN_ITEM* head = nullptr;
CLUSTERS clusters;
if( isDirty() )
searchConnections( includeZones );
@ -798,7 +837,6 @@ void CN_CONNECTIVITY_ALGO::PropagateNets()
propagateConnections();
}
void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std::vector<int>& aIslands )
{
if( aZone->GetFilledPolysList().IsEmpty() )
@ -828,6 +866,40 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std
wxLogTrace( "CN", "Found %u isolated islands\n", (unsigned)aIslands.size() );
}
void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones )
{
for ( auto& z : aZones )
{
if( z.m_zone->GetFilledPolysList().IsEmpty() )
continue;
Remove( z.m_zone );
Add( z.m_zone );
}
m_connClusters = SearchClusters( CSM_CONNECTIVITY_CHECK );
for ( auto& zone : aZones )
{
if( zone.m_zone->GetFilledPolysList().IsEmpty() )
continue;
for( auto cluster : m_connClusters )
{
if( cluster->Contains( zone.m_zone ) && cluster->IsOrphaned() )
{
for( auto z : *cluster )
{
if( z->Parent() == zone.m_zone )
{
zone.m_islands.push_back( static_cast<CN_ZONE*>(z)->SubpolyIndex() );
}
}
}
}
}
}
const CN_CONNECTIVITY_ALGO::CLUSTERS& CN_CONNECTIVITY_ALGO::GetClusters()
{
@ -995,3 +1067,8 @@ bool CN_ANCHOR::IsDangling() const
return validCount <= 1;
}
void CN_CONNECTIVITY_ALGO::SetProgressReporter( PROGRESS_REPORTER* aReporter )
{
m_progressReporter = aReporter;
}

View File

@ -53,6 +53,7 @@ class BOARD;
class BOARD_CONNECTED_ITEM;
class BOARD_ITEM;
class ZONE_CONTAINER;
class PROGRESS_REPORTER;
class CN_ANCHOR
{
@ -439,6 +440,8 @@ public:
ITER begin() { return m_items.begin(); };
ITER end() { return m_items.end(); };
CN_ITEM* operator[] ( int aIndex ) { return m_items[aIndex]; }
std::vector<CN_ANCHOR_PTR>& Anchors() { return m_anchors; }
template <class T>
@ -806,6 +809,7 @@ public:
CLUSTERS m_connClusters;
CLUSTERS m_ratsnestClusters;
std::vector<bool> m_dirtyNets;
PROGRESS_REPORTER* m_progressReporter = nullptr;
void searchConnections( bool aIncludeZones = false );
@ -883,6 +887,8 @@ public:
void PropagateNets();
void FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std::vector<int>& aIslands );
void FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones );
bool CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport );
const CLUSTERS& GetClusters();
@ -894,6 +900,7 @@ public:
void ForEachItem( std::function<void(CN_ITEM*)> aFunc );
void MarkNetAsDirty( int aNet );
void SetProgressReporter( PROGRESS_REPORTER* aReporter );
};

View File

@ -218,6 +218,10 @@ void CONNECTIVITY_DATA::FindIsolatedCopperIslands( ZONE_CONTAINER* aZone,
m_connAlgo->FindIsolatedCopperIslands( aZone, aIslands );
}
void CONNECTIVITY_DATA::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones )
{
m_connAlgo->FindIsolatedCopperIslands( aZones );
}
void CONNECTIVITY_DATA::ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>& aItems )
{
@ -617,3 +621,9 @@ void CONNECTIVITY_DATA::MarkItemNetAsDirty( BOARD_ITEM *aItem )
m_connAlgo->MarkNetAsDirty( static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode() );
}
}
void CONNECTIVITY_DATA::SetProgressReporter( PROGRESS_REPORTER* aReporter )
{
m_progressReporter = aReporter;
m_connAlgo->SetProgressReporter( m_progressReporter );
}

View File

@ -45,6 +45,7 @@ class RN_DATA;
class RN_NET;
class TRACK;
class D_PAD;
class PROGRESS_REPORTER;
struct CN_DISJOINT_NET_ENTRY
{
@ -53,6 +54,12 @@ struct CN_DISJOINT_NET_ENTRY
VECTOR2I anchorA, anchorB;
};
struct CN_ZONE_ISOLATED_ISLAND_LIST
{
ZONE_CONTAINER *m_zone;
std::vector<int> m_islands;
};
struct RN_DYNAMIC_LINE
{
int netCode;
@ -136,6 +143,7 @@ public:
* @param aIslands list of islands that have no connections (outline indices in the polygon set)
*/
void FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, std::vector<int>& aIslands );
void FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones );
/**
* Function RecalculateRatsnest()
@ -216,6 +224,8 @@ public:
void MarkItemNetAsDirty( BOARD_ITEM* aItem );
void SetProgressReporter( PROGRESS_REPORTER* aReporter );
private:
void updateRatsnest();
@ -226,6 +236,8 @@ private:
std::vector<RN_DYNAMIC_LINE> m_dynamicRatsnest;
std::vector<RN_NET*> m_nets;
PROGRESS_REPORTER* m_progressReporter;
};
#endif

View File

@ -136,13 +136,16 @@ PCB_DRAW_PANEL_GAL::~PCB_DRAW_PANEL_GAL()
}
void PCB_DRAW_PANEL_GAL::DisplayBoard( const BOARD* aBoard )
void PCB_DRAW_PANEL_GAL::DisplayBoard( BOARD* aBoard )
{
m_view->Clear();
// Load zones
for( int i = 0; i < aBoard->GetAreaCount(); ++i )
m_view->Add( (KIGFX::VIEW_ITEM*) ( aBoard->GetArea( i ) ) );
for( auto zone : aBoard->Zones() )
{
zone->CacheTriangulation();
m_view->Add( zone );
}
// Load drawings
for( auto drawing : const_cast<BOARD*>(aBoard)->Drawings() )

View File

@ -50,7 +50,7 @@ public:
* adds all items from the current board to the VIEW, so they can be displayed by GAL.
* @param aBoard is the PCB to be loaded.
*/
void DisplayBoard( const BOARD* aBoard );
void DisplayBoard( BOARD* aBoard );
/**
* Function SetWorksheet
@ -106,7 +106,7 @@ public:
protected:
KIGFX::PCB_VIEW* view() const;
///> Reassigns layer order to the initial settings.
void setDefaultLayerOrder();

View File

@ -1143,6 +1143,9 @@ void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone, int aLayer )
m_gal->SetIsStroke( true );
}
m_gal->DrawPolygon( polySet );
#if 0
for( int i = 0; i < polySet.OutlineCount(); i++ )
{
const SHAPE_LINE_CHAIN& outline = polySet.COutline( i );
@ -1164,9 +1167,12 @@ void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone, int aLayer )
m_gal->DrawPolyline( corners );
}
corners.clear();
}
#endif
}
}

View File

@ -23,6 +23,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <cstdint>
#include <thread>
#include <mutex>
#include "pcb_editor_control.h"
#include "pcb_actions.h"
@ -55,6 +57,12 @@
#include <origin_viewitem.h>
#include <profile.h>
#include <widgets/progress_reporter.h>
#ifdef USE_OPENMP
#include <omp.h>
#endif /* USE_OPENMP */
#include <tools/tool_event_utils.h>
#include <functional>
@ -82,24 +90,6 @@ TOOL_ACTION PCB_ACTIONS::trackViaSizeChanged( "pcbnew.EditorControl.trackViaSize
AS_GLOBAL, 0,
"", "", NULL, AF_NOTIFY );
// Zone actions
TOOL_ACTION PCB_ACTIONS::zoneFill( "pcbnew.EditorControl.zoneFill",
AS_GLOBAL, 0,
_( "Fill" ), _( "Fill zone(s)" ), fill_zone_xpm );
TOOL_ACTION PCB_ACTIONS::zoneFillAll( "pcbnew.EditorControl.zoneFillAll",
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZONE_FILL_OR_REFILL ),
_( "Fill All" ), _( "Fill all zones" ) );
TOOL_ACTION PCB_ACTIONS::zoneUnfill( "pcbnew.EditorControl.zoneUnfill",
AS_GLOBAL, 0,
_( "Unfill" ), _( "Unfill zone(s)" ), zone_unfill_xpm );
TOOL_ACTION PCB_ACTIONS::zoneUnfillAll( "pcbnew.EditorControl.zoneUnfillAll",
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZONE_REMOVE_FILLED ),
_( "Unfill All" ), _( "Unfill all zones" ) );
TOOL_ACTION PCB_ACTIONS::zoneMerge( "pcbnew.EditorControl.zoneMerge",
AS_GLOBAL, 0,
_( "Merge Zones" ), _( "Merge zones" ) );
@ -175,6 +165,7 @@ public:
Add( PCB_ACTIONS::drawSimilarZone );
}
protected:
CONTEXT_MENU* create() const override
{
@ -655,139 +646,6 @@ int PCB_EDITOR_CONTROL::PlaceTarget( const TOOL_EVENT& aEvent )
return 0;
}
// Zone actions
int PCB_EDITOR_CONTROL::ZoneFill( const TOOL_EVENT& aEvent )
{
auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
const auto& selection = selTool->GetSelection();
auto connectivity = getModel<BOARD>()->GetConnectivity();
BOARD_COMMIT commit( this );
for( auto item : selection )
{
assert( item->Type() == PCB_ZONE_AREA_T );
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*> ( item );
commit.Modify( zone );
m_frame->Fill_Zone( zone );
zone->SetIsFilled( true );
}
commit.Push( _( "Fill Zone" ) );
connectivity->RecalculateRatsnest();
return 0;
}
int PCB_EDITOR_CONTROL::ZoneFillAll( const TOOL_EVENT& aEvent )
{
BOARD* board = getModel<BOARD>();
auto connectivity = getModel<BOARD>()->GetConnectivity();
int areaCount = board->GetAreaCount();
const wxString fmt = _( "Filling zone %d out of %d (net %s)..." );
wxString msg;
bool aborted = false;
// Create a message with a long net name, and build a wxProgressDialog
// with a correct size to show this long net name
msg.Printf( fmt, 000, areaCount, wxT("XXXXXXXXXXXXXXXXX" ) );
auto progressDialog = new wxProgressDialog( _( "Fill All Zones" ), msg,
areaCount, frame(),
wxPD_AUTO_HIDE | wxPD_CAN_ABORT |
wxPD_APP_MODAL | wxPD_ELAPSED_TIME );
BOARD_COMMIT commit( this );
for( int i = 0; i < areaCount; ++i )
{
ZONE_CONTAINER* zone = board->GetArea( i );
msg.Printf( fmt, i, areaCount, GetChars( zone->GetNetname() ) );
commit.Modify( zone );
if( !progressDialog->Update( i, msg ) )
{
aborted = true;
break; // Aborted by user
}
m_frame->Fill_Zone( zone );
zone->SetIsFilled( true );
}
if( aborted )
commit.Revert();
else
commit.Push( _( "Fill All Zones" ) );
connectivity->RecalculateRatsnest();
progressDialog->Destroy();
return 0;
}
int PCB_EDITOR_CONTROL::ZoneUnfill( const TOOL_EVENT& aEvent )
{
auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
const auto& selection = selTool->GetSelection();
auto connectivity = getModel<BOARD>()->GetConnectivity();
BOARD_COMMIT commit( this );
for( auto item : selection )
{
assert( item->Type() == PCB_ZONE_AREA_T );
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
commit.Modify( zone );
zone->SetIsFilled( false );
zone->ClearFilledPolysList();
}
commit.Push( _( "Unfill Zone" ) );
connectivity->RecalculateRatsnest();
return 0;
}
int PCB_EDITOR_CONTROL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
{
BOARD* board = getModel<BOARD>();
auto connectivity = getModel<BOARD>()->GetConnectivity();
BOARD_COMMIT commit( this );
for( int i = 0; i < board->GetAreaCount(); ++i )
{
ZONE_CONTAINER* zone = board->GetArea( i );
commit.Modify( zone );
zone->SetIsFilled( false );
zone->ClearFilledPolysList();
}
commit.Push( _( "Unfill All Zones" ) );
connectivity->RecalculateRatsnest();
return 0;
}
static bool mergeZones( BOARD_COMMIT& aCommit, std::vector<ZONE_CONTAINER *>& aOriginZones,
std::vector<ZONE_CONTAINER *>& aMergedZones )
{
@ -819,6 +677,7 @@ static bool mergeZones( BOARD_COMMIT& aCommit, std::vector<ZONE_CONTAINER *>& aO
aOriginZones[0]->SetLocalFlags( 1 );
aOriginZones[0]->Hatch();
aOriginZones[0]->CacheTriangulation();
return true;
}
@ -1250,10 +1109,6 @@ void PCB_EDITOR_CONTROL::setTransitions()
Go( &PCB_EDITOR_CONTROL::ViaSizeDec, PCB_ACTIONS::viaSizeDec.MakeEvent() );
// Zone actions
Go( &PCB_EDITOR_CONTROL::ZoneFill, PCB_ACTIONS::zoneFill.MakeEvent() );
Go( &PCB_EDITOR_CONTROL::ZoneFillAll, PCB_ACTIONS::zoneFillAll.MakeEvent() );
Go( &PCB_EDITOR_CONTROL::ZoneUnfill, PCB_ACTIONS::zoneUnfill.MakeEvent() );
Go( &PCB_EDITOR_CONTROL::ZoneUnfillAll, PCB_ACTIONS::zoneUnfillAll.MakeEvent() );
Go( &PCB_EDITOR_CONTROL::ZoneMerge, PCB_ACTIONS::zoneMerge.MakeEvent() );
Go( &PCB_EDITOR_CONTROL::ZoneDuplicate, PCB_ACTIONS::zoneDuplicate.MakeEvent() );

View File

@ -57,10 +57,6 @@ public:
int ViaSizeDec( const TOOL_EVENT& aEvent );
// Zone actions
int ZoneFill( const TOOL_EVENT& aEvent );
int ZoneFillAll( const TOOL_EVENT& aEvent );
int ZoneUnfill( const TOOL_EVENT& aEvent );
int ZoneUnfillAll( const TOOL_EVENT& aEvent );
int ZoneMerge( const TOOL_EVENT& aEvent );
///> Duplicates a zone onto a layer (prompts for new layer)

View File

@ -40,6 +40,7 @@
#include <tools/pad_tool.h>
#include <tools/microwave_tool.h>
#include <tools/position_relative_tool.h>
#include <tools/zone_filler_tool.h>
#include <tools/pcb_actions.h>
#include <router/router_tool.h>
@ -62,4 +63,5 @@ void PCB_ACTIONS::RegisterAllTools( TOOL_MANAGER* aToolManager )
aToolManager->RegisterTool( new ALIGN_DISTRIBUTE_TOOL );
aToolManager->RegisterTool( new MICROWAVE_TOOL );
aToolManager->RegisterTool( new POSITION_RELATIVE_TOOL );
aToolManager->RegisterTool( new ZONE_FILLER_TOOL );
}

View File

@ -0,0 +1,327 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2017 CERN
* Copyright (C) 2014-2017 KiCad Developers, see AUTHORS.txt for contributors.
* @author Maciej Suminski <maciej.suminski@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 <cstdint>
#include <thread>
#include <mutex>
#include <painter.h>
#include <project.h>
#include <pcbnew_id.h>
#include <wxPcbStruct.h>
#include <class_board.h>
#include <class_zone.h>
#include <pcb_draw_panel_gal.h>
#include <class_module.h>
#include <connectivity_data.h>
#include <board_commit.h>
#include <widgets/progress_reporter.h>
#include <tool/tool_manager.h>
#include <bitmaps.h>
#include <hotkeys.h>
#include "pcb_actions.h"
#include "selection_tool.h"
#include "zone_filler_tool.h"
#ifdef USE_OPENMP
#include <omp.h>
#endif /* USE_OPENMP */
// Zone actions
TOOL_ACTION PCB_ACTIONS::zoneFill( "pcbnew.ZoneFiller.zoneFill",
AS_GLOBAL, 0,
_( "Fill" ), _( "Fill zone(s)" ), fill_zone_xpm );
TOOL_ACTION PCB_ACTIONS::zoneFillAll( "pcbnew.ZoneFiller.zoneFillAll",
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZONE_FILL_OR_REFILL ),
_( "Fill All" ), _( "Fill all zones" ) );
TOOL_ACTION PCB_ACTIONS::zoneUnfill( "pcbnew.ZoneFiller.zoneUnfill",
AS_GLOBAL, 0,
_( "Unfill" ), _( "Unfill zone(s)" ), zone_unfill_xpm );
TOOL_ACTION PCB_ACTIONS::zoneUnfillAll( "pcbnew.ZoneFiller.zoneUnfillAll",
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZONE_REMOVE_FILLED ),
_( "Unfill All" ), _( "Unfill all zones" ) );
class ZONE_FILLER
{
public:
ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit );
~ZONE_FILLER();
void SetProgressReporter( PROGRESS_REPORTER* aReporter );
void Fill( std::vector<ZONE_CONTAINER*> aZones );
void Unfill( std::vector<ZONE_CONTAINER*> aZones );
private:
COMMIT* m_commit;
PROGRESS_REPORTER* m_progressReporter;
BOARD* m_board;
};
ZONE_FILLER::ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit ) :
m_commit( aCommit ),
m_board( aBoard )
{
}
ZONE_FILLER::~ZONE_FILLER()
{
}
void ZONE_FILLER::SetProgressReporter( PROGRESS_REPORTER* aReporter )
{
m_progressReporter = aReporter;
}
void ZONE_FILLER::Fill( std::vector<ZONE_CONTAINER*> aZones )
{
std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> toFill;
assert( m_commit );
// Remove segment zones
m_board->m_Zone.DeleteAll();
int ii;
for( auto zone : aZones )
{
// Keepout zones are not filled
if( zone->GetIsKeepout() )
continue;
CN_ZONE_ISOLATED_ISLAND_LIST l;
l.m_zone = zone;
toFill.push_back( l );
}
int zoneCount = m_board->GetAreaCount();
for( int i = 0; i < toFill.size(); i++ )
{
m_commit->Modify( toFill[i].m_zone );
}
if( m_progressReporter )
{
m_progressReporter->Report( _( "Calculating zone fills..." ) );
m_progressReporter->SetMaxProgress( toFill.size() );
}
#ifdef USE_OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for( int i = 0; i < toFill.size(); i++ )
{
toFill[i].m_zone->BuildFilledSolidAreasPolygons( m_board );
m_progressReporter->AdvanceProgress();
}
if( m_progressReporter )
{
m_progressReporter->AdvancePhase();
m_progressReporter->Report( _( "Removing insulated copper islands..." ) );
}
m_board->GetConnectivity()->SetProgressReporter( m_progressReporter );
m_board->GetConnectivity()->FindIsolatedCopperIslands( toFill );
for( auto& zone : toFill )
{
std::sort( zone.m_islands.begin(), zone.m_islands.end(), std::greater<int>() );
SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList();
for( auto idx : zone.m_islands )
{
poly.DeletePolygon( idx );
}
zone.m_zone->AddFilledPolysList( poly );
}
if( m_progressReporter )
{
m_progressReporter->AdvancePhase();
m_progressReporter->Report( _( "Caching polygon triangulations..." ) );
m_progressReporter->SetMaxProgress( toFill.size() );
}
#ifdef USE_OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for( int i = 0; i < toFill.size(); i++ )
{
m_progressReporter->AdvanceProgress();
toFill[i].m_zone->CacheTriangulation();
}
m_progressReporter->AdvancePhase();
m_progressReporter->Report( _( "Committing changes..." ) );
m_commit->Push( _( "Fill Zones" ), false );
}
ZONE_FILLER_TOOL::ZONE_FILLER_TOOL() :
PCB_TOOL( "pcbnew.ZoneFiller" )
{
}
ZONE_FILLER_TOOL::~ZONE_FILLER_TOOL()
{
}
void ZONE_FILLER_TOOL::Reset( RESET_REASON aReason )
{
}
// Zone actions
int ZONE_FILLER_TOOL::ZoneFill( const TOOL_EVENT& aEvent )
{
auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
const auto& selection = selTool->GetSelection();
std::vector<ZONE_CONTAINER*> toFill;
BOARD_COMMIT commit( this );
for( auto item : selection )
{
assert( item->Type() == PCB_ZONE_AREA_T );
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*> ( item );
toFill.push_back(zone);
}
std::unique_ptr<WX_PROGRESS_REPORTER> progressReporter(
new WX_PROGRESS_REPORTER( frame(), _( "Fill Zones" ), 3 )
);
ZONE_FILLER filler( board(), &commit );
filler.SetProgressReporter( progressReporter.get() );
filler.Fill( toFill );
return 0;
}
int ZONE_FILLER_TOOL::ZoneFillAll( const TOOL_EVENT& aEvent )
{
std::vector<ZONE_CONTAINER*> toFill;
BOARD_COMMIT commit( this );
for( auto zone : board()->Zones() )
{
toFill.push_back(zone);
}
std::unique_ptr<WX_PROGRESS_REPORTER> progressReporter(
new WX_PROGRESS_REPORTER( frame(), _( "Fill All Zones" ), 3 )
);
ZONE_FILLER filler( board(), &commit );
filler.SetProgressReporter( progressReporter.get() );
filler.Fill( toFill );
return 0;
}
int ZONE_FILLER_TOOL::ZoneUnfill( const TOOL_EVENT& aEvent )
{
auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
const auto& selection = selTool->GetSelection();
auto connectivity = getModel<BOARD>()->GetConnectivity();
BOARD_COMMIT commit( this );
for( auto item : selection )
{
assert( item->Type() == PCB_ZONE_AREA_T );
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
commit.Modify( zone );
zone->SetIsFilled( false );
zone->ClearFilledPolysList();
}
commit.Push( _( "Unfill Zone" ) );
connectivity->RecalculateRatsnest();
return 0;
}
int ZONE_FILLER_TOOL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
{
BOARD* board = getModel<BOARD>();
auto connectivity = getModel<BOARD>()->GetConnectivity();
BOARD_COMMIT commit( this );
for( int i = 0; i < board->GetAreaCount(); ++i )
{
ZONE_CONTAINER* zone = board->GetArea( i );
commit.Modify( zone );
zone->SetIsFilled( false );
zone->ClearFilledPolysList();
}
commit.Push( _( "Unfill All Zones" ) );
connectivity->RecalculateRatsnest();
return 0;
}
void ZONE_FILLER_TOOL::setTransitions()
{
// Zone actions
Go( &ZONE_FILLER_TOOL::ZoneFill, PCB_ACTIONS::zoneFill.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneFillAll, PCB_ACTIONS::zoneFillAll.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneUnfill, PCB_ACTIONS::zoneUnfill.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneUnfillAll, PCB_ACTIONS::zoneUnfillAll.MakeEvent() );
}

Some files were not shown because too many files have changed in this diff Show More