pcb_new: CONNECTIVITY_DATA now keeps a cache of DRC from-tos

This commit is contained in:
Tomasz Wlostowski 2020-09-25 20:26:58 +02:00
parent bc7369d70c
commit 7b7c3bde88
8 changed files with 403 additions and 4 deletions

View File

@ -509,6 +509,7 @@ set( PCB_COMMON_SRCS
${CMAKE_SOURCE_DIR}/pcbnew/connectivity/connectivity_algo.cpp
${CMAKE_SOURCE_DIR}/pcbnew/connectivity/connectivity_items.cpp
${CMAKE_SOURCE_DIR}/pcbnew/connectivity/connectivity_data.cpp
${CMAKE_SOURCE_DIR}/pcbnew/connectivity/from_to_cache.cpp
${CMAKE_SOURCE_DIR}/pcbnew/convert_drawsegment_list_to_polygon.cpp
${CMAKE_SOURCE_DIR}/pcbnew/drc/drc_engine.cpp
${CMAKE_SOURCE_DIR}/pcbnew/drc/drc_item.cpp

View File

@ -11,6 +11,7 @@ set( PCBNEW_CONN_SRCS
connectivity_algo.cpp
connectivity_data.cpp
connectivity_items.cpp
from_to_cache.cpp
)
add_library( connectivity STATIC ${PCBNEW_CONN_SRCS} )

View File

@ -33,12 +33,15 @@
#include <connectivity/connectivity_data.h>
#include <connectivity/connectivity_algo.h>
#include <connectivity/from_to_cache.h>
#include <ratsnest/ratsnest_data.h>
CONNECTIVITY_DATA::CONNECTIVITY_DATA()
{
m_connAlgo.reset( new CN_CONNECTIVITY_ALGO );
m_progressReporter = nullptr;
m_fromToCache.reset( new FROM_TO_CACHE );
}
@ -47,6 +50,7 @@ CONNECTIVITY_DATA::CONNECTIVITY_DATA( const std::vector<BOARD_ITEM*>& aItems, bo
{
Build( aItems );
m_progressReporter = nullptr;
m_fromToCache.reset( new FROM_TO_CACHE );
}

View File

@ -38,6 +38,7 @@
#include <geometry/shape_poly_set.h>
#include <class_zone.h>
class FROM_TO_CACHE;
class CN_CLUSTER;
class CN_CONNECTIVITY_ALGO;
class CN_EDGE;
@ -269,6 +270,11 @@ public:
const std::vector<CN_EDGE> GetRatsnestForComponent( MODULE* aComponent, bool aSkipInternalConnections = false );
#endif
std::shared_ptr<FROM_TO_CACHE> GetFromToCache()
{
return m_fromToCache;
}
private:
void updateRatsnest();
@ -282,7 +288,7 @@ private:
void addRatsnestCluster( const std::shared_ptr<CN_CLUSTER>& aCluster );
std::shared_ptr<CN_CONNECTIVITY_ALGO> m_connAlgo;
std::shared_ptr<FROM_TO_CACHE> m_fromToCache;
std::vector<RN_DYNAMIC_LINE> m_dynamicRatsnest;
std::vector<RN_NET*> m_nets;

View File

@ -0,0 +1,268 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004-2020 KiCad Developers.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <cstdio>
#include <memory>
#include <reporter.h>
#include <class_board.h>
#include <class_track.h>
#include <pcb_expr_evaluator.h>
#include <connectivity/connectivity_data.h>
#include <connectivity/connectivity_algo.h>
#include <connectivity/from_to_cache.h>
void FROM_TO_CACHE::buildEndpointList( )
{
m_ftEndpoints.clear();
for( auto mod : m_board->Modules() )
{
for( auto pad : mod->Pads() )
{
FT_ENDPOINT ent;
ent.name = mod->GetReference() + "-" + pad->GetName();
ent.parent = pad;
m_ftEndpoints.push_back( ent );
ent.name = mod->GetReference();
ent.parent = pad;
m_ftEndpoints.push_back( ent );
}
}
}
enum PATH_STATUS {
PS_OK = 0,
PS_MULTIPLE_PATHS = -1,
PS_NO_PATH = -2
};
static bool isVertexVisited( CN_ITEM* v, const std::vector<CN_ITEM*>& path )
{
for( auto u : path )
{
if ( u == v )
return true;
}
return false;
}
static PATH_STATUS uniquePathBetweenNodes( CN_ITEM* u, CN_ITEM* v, std::vector<CN_ITEM*>& outPath )
{
using Path = std::vector<CN_ITEM*>;
std::deque<Path> Q;
Path p;
int pathFound = false;
p.push_back( u );
Q.push_back( p );
while( Q.size() )
{
Path path = Q.front();
Q.pop_front();
CN_ITEM *last = path.back();
if( last == v )
{
outPath = path;
if( pathFound )
return PS_MULTIPLE_PATHS;
pathFound = true;
}
for( auto ci : last->ConnectedItems() )
{
bool vertexVisited = isVertexVisited(ci, path);
for( auto &p : Q )
if (isVertexVisited(ci, p))
{
vertexVisited = true;
break;
}
if (!vertexVisited) {
Path newpath(path);
newpath.push_back(ci);
Q.push_back(newpath);
}
}
}
return pathFound ? PS_OK : PS_NO_PATH;
};
int FROM_TO_CACHE::cacheFromToPaths( const wxString& aFrom, const wxString& aTo )
{
std::vector<FT_PATH> paths;
auto connectivity = m_board->GetConnectivity();
auto cnAlgo = connectivity->GetConnectivityAlgo();
for( auto& endpoint : m_ftEndpoints )
{
if( WildCompareString( aFrom, endpoint.name, false ) )
{
FT_PATH p;
p.net = endpoint.parent->GetNetCode();
p.from = endpoint.parent;
p.to = nullptr;
paths.push_back(p);
}
}
for( auto &path : paths )
{
int count = 0;
auto netName = path.from->GetNetname();
wxString fromName = path.from->GetParent()->GetReference() + "-" + path.from->GetName();
const KICAD_T onlyRouting[] = { PCB_PAD_T, PCB_ARC_T, PCB_VIA_T, PCB_TRACE_T, EOT };
auto padCandidates = connectivity->GetConnectedItems( path.from, onlyRouting );
D_PAD* toPad = nullptr;
for( auto pitem : padCandidates )
{
if( pitem == path.from )
continue;
if( pitem->Type() != PCB_PAD_T )
continue;
D_PAD *pad = static_cast<D_PAD*>( pitem );
wxString toName = pad->GetParent()->GetReference() + "-" + pad->GetName();
for ( auto& endpoint : m_ftEndpoints )
{
if( pad == endpoint.parent )
{
if( WildCompareString( aTo, endpoint.name, false ) )
{
count++;
toPad = endpoint.parent;
path.to = toPad;
path.fromName = fromName;
path.toName = toName;
path.fromWildcard = aFrom;
path.toWildcard = aTo;
if( count >= 2 )
{
// fixme: report this somewhere?
//printf("Multiple targets found, aborting...\n");
path.to = nullptr;
}
}
}
}
}
}
int newPaths = 0;
for( auto &path : paths )
{
if( !path.from || !path.to )
continue;
CN_ITEM *cnFrom = cnAlgo->ItemEntry( path.from ).GetItems().front();
CN_ITEM *cnTo = cnAlgo->ItemEntry( path.to ).GetItems().front();
CN_ITEM::CONNECTED_ITEMS upath;
auto result = uniquePathBetweenNodes( cnFrom, cnTo, upath );
if( result == PS_OK )
path.isUnique = true;
else
path.isUnique = false;
//printf( "%s\n", (const char *) wxString::Format( _("Check path: %s -> %s (net %s)"), path.fromName, path.toName, cnFrom->Parent()->GetNetname() ) );
if( result == PS_NO_PATH )
continue;
for( auto item : upath )
{
path.pathItems.insert( item->Parent() );
}
m_ftPaths.push_back(path);
newPaths++;
}
//reportAux( _("Cached %d paths\n"), newPaths );
return newPaths;
}
bool FROM_TO_CACHE::IsOnFromToPath( BOARD_CONNECTED_ITEM* aItem, const wxString& aFrom, const wxString& aTo )
{
int nFromTosFound = 0;
if( !m_board )
return false;
//printf("Check %d cached paths [%p]\n", m_ftPaths.size(), aItem );
for( int attempt = 0; attempt < 2; attempt++ )
{
// item already belongs to path
for( auto& ftPath : m_ftPaths )
{
if( aFrom == ftPath.fromWildcard &&
aTo == ftPath.toWildcard )
{
nFromTosFound++;
if( ftPath.pathItems.count( aItem ) )
{
// printf("Found cached path for %p [%s->%s]\n", aItem, (const char *)ftPath.fromName, (const char *) ftPath.toName );
return true;
}
}
}
if( !nFromTosFound )
cacheFromToPaths( aFrom, aTo );
else
return false;
}
return false;
}
void FROM_TO_CACHE::Rebuild( BOARD* aBoard )
{
m_board = aBoard;
buildEndpointList();
m_ftPaths.clear();
}

View File

@ -0,0 +1,74 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004-2020 KiCad Developers.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FROM_TO_CACHE_H
#define __FROM_TO_CACHE_H
#include <set>
#include <common.h>
class D_PAD;
class BOARD_CONNECTED_ITEM;
class FROM_TO_CACHE
{
public:
struct FT_ENDPOINT
{
wxString name;
D_PAD* parent;
};
struct FT_PATH
{
int net;
D_PAD *from;
D_PAD *to;
wxString fromName, toName;
wxString fromWildcard, toWildcard;
bool isUnique;
std::set<BOARD_CONNECTED_ITEM*> pathItems;
};
FROM_TO_CACHE( BOARD* aBoard = nullptr ) :
m_board( aBoard )
{
}
~FROM_TO_CACHE()
{
}
void Rebuild( BOARD* aBoard );
bool IsOnFromToPath( BOARD_CONNECTED_ITEM* aItem, const wxString& aFrom, const wxString& aTo );
private:
int cacheFromToPaths( const wxString& aFrom, const wxString& aTo );
void buildEndpointList();
std::vector<FT_ENDPOINT> m_ftEndpoints;
std::vector<FT_PATH> m_ftPaths;
BOARD* m_board;
};
#endif

View File

@ -27,8 +27,55 @@
#include <reporter.h>
#include <class_board.h>
#include <class_track.h>
#include <pcb_expr_evaluator.h>
#include <connectivity/connectivity_data.h>
#include <connectivity/connectivity_algo.h>
#include <connectivity/from_to_cache.h>
bool exprFromTo( LIBEVAL::CONTEXT* aCtx, void* self )
{
PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
LIBEVAL::VALUE* result = aCtx->AllocValue();
LIBEVAL::VALUE* argTo = aCtx->Pop();
LIBEVAL::VALUE* argFrom = aCtx->Pop();
result->Set(0.0);
aCtx->Push( result );
if(!item)
return false;
auto ftCache = item->GetBoard()->GetConnectivity()->GetFromToCache();
if( !ftCache )
{
wxLogWarning( "Attempting to call fromTo() with non-existent from-to cache, aborting...");
return true;
}
int r =0 ;
if( ftCache->IsOnFromToPath( static_cast<BOARD_CONNECTED_ITEM*>( item ),
argFrom->AsString(), argTo->AsString() ) )
{
result->Set(1.0);
r = 1;
}
/*printf("isonfromto %p %s %s -> %d\n", static_cast<BOARD_CONNECTED_ITEM*>( item ),
(const char *)argFrom->AsString(),
(const char *)argTo->AsString(), r );*/
return true;
}
static void onLayer( LIBEVAL::CONTEXT* aCtx, void *self )
{
@ -286,8 +333,6 @@ static void isBlindBuriedVia( LIBEVAL::CONTEXT* aCtx, void* self )
}
extern void exprFromTo( LIBEVAL::CONTEXT* aCtx, void* self );
PCB_EXPR_BUILTIN_FUNCTIONS::PCB_EXPR_BUILTIN_FUNCTIONS()
{
RegisterAllFunctions();
@ -305,6 +350,7 @@ void PCB_EXPR_BUILTIN_FUNCTIONS::RegisterAllFunctions()
RegisterFunc( "isBlindBuriedVia()", isBlindBuriedVia );
RegisterFunc( "memberOf('x')", memberOf );
RegisterFunc( "fromTo('x','y')", exprFromTo );
//RegisterFunc( "isDiffPair()", exprFromTo );
}

View File

@ -142,7 +142,6 @@ public:
wxString funcName = funcSignature.BeforeFirst( '(' );
m_funcs[std::string( funcName.Lower() )] = std::move( funcPtr );
m_funcSigs.Add( funcSignature );
printf("Register '%s'\n", (const char *) funcName.Lower() );
}
void RegisterAllFunctions();