Browse Source
qa/pns: refactored the P&S debug tool:
qa/pns: refactored the P&S debug tool:
- factored out 'business' code from the UI code - moved to the new DEBUG_DECORATOR interface - UI-less log file and log player classes as a step towards P&S unit tests7.0
19 changed files with 2500 additions and 1007 deletions
-
3pcbnew/router/pns_logger.h
-
8qa/pns/CMakeLists.txt
-
177qa/pns/label_manager.cpp
-
25qa/pns/label_manager.h
-
316qa/pns/logviewer.fbp
-
41qa/pns/main.cpp
-
475qa/pns/pns_log.cpp
-
280qa/pns/pns_log.h
-
130qa/pns/pns_log_file.cpp
-
75qa/pns/pns_log_file.h
-
255qa/pns/pns_log_player.cpp
-
100qa/pns/pns_log_player.h
-
306qa/pns/pns_log_viewer.cpp
-
819qa/pns/pns_log_viewer_frame.cpp
-
59qa/pns/pns_log_viewer_frame.h
-
35qa/pns/pns_log_viewer_frame_base.cpp
-
11qa/pns/pns_log_viewer_frame_base.h
-
278qa/pns/pns_test_debug_decorator.cpp
-
114qa/pns/pns_test_debug_decorator.h
@ -0,0 +1,177 @@ |
|||
#include <gal/graphics_abstraction_layer.h>
|
|||
#include <gal/color4d.h>
|
|||
#include <view/view_overlay.h>
|
|||
|
|||
#include "label_manager.h"
|
|||
|
|||
using KIGFX::GAL; |
|||
using KIGFX::COLOR4D; |
|||
using KIGFX::VIEW_OVERLAY; |
|||
|
|||
LABEL_MANAGER::LABEL_MANAGER( GAL* aGal ) : m_gal( aGal ) |
|||
{ |
|||
}; |
|||
|
|||
|
|||
LABEL_MANAGER::~LABEL_MANAGER() |
|||
{ |
|||
} |
|||
|
|||
|
|||
void LABEL_MANAGER::Add( VECTOR2I target, wxString msg, COLOR4D color ) |
|||
{ |
|||
LABEL lbl; |
|||
|
|||
lbl.m_target = target; |
|||
lbl.m_msg = msg; |
|||
lbl.m_color = color; |
|||
m_gal->SetGlyphSize( VECTOR2D( m_textSize, m_textSize ) ); |
|||
|
|||
KIFONT::FONT* strokeFont = KIFONT::FONT::GetFont( wxEmptyString ); |
|||
UTF8 text( msg ); |
|||
VECTOR2I textDims = strokeFont->StringBoundaryLimits( text, VECTOR2D( m_textSize, m_textSize ), |
|||
m_textSize/8, false, false ); |
|||
|
|||
lbl.m_bbox.SetOrigin( lbl.m_target - textDims - VECTOR2I( m_textSize, m_textSize ) ); |
|||
lbl.m_bbox.SetSize( textDims ); |
|||
m_labels.push_back( lbl ); |
|||
} |
|||
|
|||
|
|||
void LABEL_MANAGER::Add( const SHAPE_LINE_CHAIN& aL, COLOR4D color ) |
|||
{ |
|||
for( int i = 0; i < aL.PointCount(); i++ ) |
|||
{ |
|||
char msg[1024]; |
|||
snprintf( msg, sizeof( msg ), "%d", i ); |
|||
Add( aL.CPoint( i ), msg, color ); |
|||
} |
|||
} |
|||
|
|||
void LABEL_MANAGER::Redraw( VIEW_OVERLAY* aOvl ) |
|||
{ |
|||
recalculate(); |
|||
|
|||
for( auto& lbl : m_labels ) |
|||
{ |
|||
aOvl->SetIsFill( false ); |
|||
aOvl->SetIsStroke( true ); |
|||
aOvl->SetLineWidth( 10000 ); |
|||
aOvl->SetStrokeColor( lbl.m_color.Brighten( 0.7 ) ); |
|||
aOvl->Rectangle( lbl.m_bbox.GetOrigin(), lbl.m_bbox.GetEnd() ); |
|||
aOvl->BitmapText( lbl.m_msg, lbl.m_bbox.Centre(), ANGLE_HORIZONTAL ); |
|||
VECTOR2I nearest = nearestBoxCorner( lbl.m_bbox, lbl.m_target ); |
|||
aOvl->Line( lbl.m_target, nearest ); |
|||
} |
|||
} |
|||
|
|||
|
|||
VECTOR2I LABEL_MANAGER::nearestBoxCorner( BOX2I b, VECTOR2I p ) |
|||
{ |
|||
VECTOR2I ptest[4] = { b.GetPosition(), b.GetPosition() + VECTOR2I( b.GetWidth(), 0 ), |
|||
b.GetPosition() + VECTOR2I( b.GetWidth(), b.GetHeight() ), |
|||
b.GetPosition() + VECTOR2I( 0, b.GetHeight() ) }; |
|||
|
|||
int bestDist = INT_MAX; |
|||
VECTOR2I rv; |
|||
|
|||
for( int i = 0; i < 4; i++ ) |
|||
{ |
|||
int dist = ( ptest[i] - p ).EuclideanNorm(); |
|||
|
|||
if( dist < bestDist ) |
|||
{ |
|||
bestDist = dist; |
|||
rv = ptest[i]; |
|||
} |
|||
} |
|||
|
|||
return rv; |
|||
} |
|||
|
|||
|
|||
VECTOR2I LABEL_MANAGER::boxMtv( BOX2I b1, BOX2I b2 ) |
|||
{ |
|||
VECTOR2I rv( 0, 0 ); |
|||
|
|||
b1.Normalize(); |
|||
b2.Normalize(); |
|||
|
|||
if( !b1.Intersects( b2 ) ) |
|||
return rv; |
|||
|
|||
int bestDist = INT_MAX; |
|||
|
|||
VECTOR2I p[4] = { b2.GetPosition(), b2.GetPosition() + VECTOR2I( b2.GetWidth(), 0 ), |
|||
b2.GetPosition() + VECTOR2I( b2.GetWidth(), b2.GetHeight() ), |
|||
b2.GetPosition() + VECTOR2I( 0, b2.GetHeight() ) }; |
|||
|
|||
for( int i = 0; i < 4; i++ ) |
|||
{ |
|||
if( b1.Contains( p[i] ) ) |
|||
{ |
|||
// printf("CONT %d\n", i );
|
|||
VECTOR2I dp[4] = { VECTOR2I( b1.GetEnd().x - p[i].x + 1, 0 ), |
|||
VECTOR2I( b1.GetPosition().x - p[i].x - 1, 0 ), |
|||
VECTOR2I( 0, b1.GetEnd().y - p[i].y + 1 ), |
|||
VECTOR2I( 0, b1.GetPosition().y - p[i].y - 1 ) }; |
|||
|
|||
for( int j = 0; j < 4; j++ ) |
|||
{ |
|||
BOX2I btest( b2 ); |
|||
btest.Move( dp[j] ); |
|||
|
|||
if( !b1.Intersects( btest ) ) |
|||
{ |
|||
int dist = dp[j].EuclideanNorm(); |
|||
|
|||
if( dist < bestDist ) |
|||
{ |
|||
bestDist = dist; |
|||
rv = dp[j]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
return rv; |
|||
} |
|||
|
|||
|
|||
void LABEL_MANAGER::recalculate() |
|||
{ |
|||
int iterLimit = 5; |
|||
|
|||
while( iterLimit > 0 ) |
|||
{ |
|||
bool collisionsFound = false; |
|||
|
|||
for( int i = 0; i < m_labels.size(); i++ ) |
|||
{ |
|||
for( int j = 0; j < m_labels.size(); j++ ) |
|||
{ |
|||
if( i == j ) |
|||
continue; |
|||
|
|||
auto bb_i = m_labels[i].m_bbox; |
|||
auto bb_j = m_labels[j].m_bbox; |
|||
|
|||
bb_i.Inflate( 100000 ); |
|||
bb_j.Inflate( 100000 ); |
|||
VECTOR2I mtv = boxMtv( bb_i, bb_j ); |
|||
|
|||
if( mtv.x || mtv.y ) |
|||
{ |
|||
m_labels[i].m_bbox.Move( -mtv ); |
|||
collisionsFound = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if( !collisionsFound ) |
|||
break; |
|||
|
|||
iterLimit--; |
|||
} |
|||
} |
@ -1,37 +1,40 @@ |
|||
#ifndef __LABEL_MANAGER_H |
|||
#define __LABEL_MANAGER_H |
|||
|
|||
#include <wx/wx.h> |
|||
|
|||
#include <gal/graphics_abstraction_layer.h> |
|||
#include <gal/color4d.h> |
|||
#include <math/vector2d.h> |
|||
#include <math/box2.h> |
|||
#include <view/view_overlay.h> |
|||
#include <geometry/shape_line_chain.h> |
|||
|
|||
class LABEL_MANAGER |
|||
{ |
|||
public: |
|||
struct LABEL |
|||
{ |
|||
COLOR4D m_color; |
|||
std::string m_msg; |
|||
VECTOR2I m_target; |
|||
BOX2I m_bbox; |
|||
KIGFX::COLOR4D m_color; |
|||
wxString m_msg; |
|||
VECTOR2I m_target; |
|||
BOX2I m_bbox; |
|||
}; |
|||
|
|||
LABEL_MANAGER( KIGFX::GAL* aGal ); |
|||
~LABEL_MANAGER( ); |
|||
~LABEL_MANAGER(); |
|||
|
|||
void Add( VECTOR2I target, std::string msg, COLOR4D color ); |
|||
void Add( const SHAPE_LINE_CHAIN& aL, COLOR4D color ); |
|||
void Add( VECTOR2I target, wxString msg, KIGFX::COLOR4D color ); |
|||
void Add( const SHAPE_LINE_CHAIN& aL, KIGFX::COLOR4D color ); |
|||
void Redraw( KIGFX::VIEW_OVERLAY* aOvl ); |
|||
|
|||
private: |
|||
|
|||
VECTOR2I nearestBoxCorner( BOX2I b, VECTOR2I p ); |
|||
VECTOR2I boxMtv( BOX2I b1, BOX2I b2 ); |
|||
void recalculate(); |
|||
void recalculate(); |
|||
|
|||
KIGFX::GAL* m_gal; |
|||
int m_textSize = 100000; |
|||
KIGFX::GAL* m_gal; |
|||
int m_textSize = 100000; |
|||
std::vector<LABEL> m_labels; |
|||
}; |
|||
|
@ -0,0 +1,41 @@ |
|||
#include <qa_utils/utility_registry.h>
|
|||
|
|||
#include "pns_log_file.h"
|
|||
#include "pns_log_viewer_frame.h"
|
|||
|
|||
int replay_main_func( int argc, char* argv[] ) |
|||
{ |
|||
auto frame = new PNS_LOG_VIEWER_FRAME( nullptr ); |
|||
|
|||
// drcCreateTestsProviderClearance();
|
|||
// drcCreateTestsProviderEdgeClearance();
|
|||
|
|||
if( argc >= 2 && std::string( argv[1] ) == "-h" ) |
|||
{ |
|||
printf( "PNS Log (Re)player. Allows to step through the log written by the ROUTER_TOOL " |
|||
"in debug KiCad builds. " ); |
|||
printf( "Requires a board file with UUIDs and a matching log file. Both are written to " |
|||
"/tmp when you press '0' during routing." ); |
|||
return 0; |
|||
} |
|||
|
|||
if( argc < 3 ) |
|||
{ |
|||
printf( "Expected parameters: log_file.log board_file.dump\n" ); |
|||
return 0; |
|||
} |
|||
|
|||
PNS_LOG_FILE* logFile = new PNS_LOG_FILE; |
|||
logFile->Load( argv[1], argv[2] ); |
|||
|
|||
frame->SetLogFile( logFile ); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
static bool registered = UTILITY_REGISTRY::Register( { |
|||
"replay", |
|||
"PNS Log Player", |
|||
replay_main_func, |
|||
} ); |
@ -1,475 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020-2021 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 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 "pns_log.h"
|
|||
|
|||
#include <qa/drc_proto/drc_proto.h>
|
|||
|
|||
#include <board_design_settings.h>
|
|||
#include <pcbnew/drc/drc_engine.h>
|
|||
#include <pcbnew/drc/drc_test_provider.h>
|
|||
#include <pns_arc.h>
|
|||
|
|||
|
|||
#define PNSLOGINFO PNS::DEBUG_DECORATOR::SRC_LOCATION_INFO( __FILE__, __FUNCTION__, __LINE__ )
|
|||
|
|||
using namespace PNS; |
|||
|
|||
static const wxString readLine( FILE* f ) |
|||
{ |
|||
char str[16384]; |
|||
fgets( str, sizeof( str ) - 1, f ); |
|||
return wxString( str ); |
|||
} |
|||
|
|||
|
|||
PNS_LOG_FILE::PNS_LOG_FILE() |
|||
{ |
|||
m_routerSettings.reset( new PNS::ROUTING_SETTINGS( nullptr, "" ) ); |
|||
} |
|||
|
|||
|
|||
bool PNS_LOG_FILE::Load( const std::string& logName, const std::string boardName ) |
|||
{ |
|||
FILE* f = fopen( logName.c_str(), "rb" ); |
|||
|
|||
if( !f ) |
|||
return false; |
|||
|
|||
while( !feof( f ) ) |
|||
{ |
|||
wxStringTokenizer tokens( readLine( f ) ); |
|||
|
|||
if( !tokens.CountTokens() ) |
|||
continue; |
|||
|
|||
wxString cmd = tokens.GetNextToken(); |
|||
|
|||
if( cmd == "event" ) |
|||
{ |
|||
EVENT_ENTRY evt; |
|||
evt.p.x = wxAtoi( tokens.GetNextToken() ); |
|||
evt.p.y = wxAtoi( tokens.GetNextToken() ); |
|||
evt.type = (PNS::LOGGER::EVENT_TYPE) wxAtoi( tokens.GetNextToken() ); |
|||
evt.uuid = KIID( tokens.GetNextToken() ); |
|||
m_events.push_back( evt ); |
|||
} |
|||
else if( cmd == "config" ) |
|||
{ |
|||
m_routerSettings->SetMode( (PNS::PNS_MODE) wxAtoi( tokens.GetNextToken() ) ); |
|||
m_routerSettings->SetRemoveLoops( wxAtoi( tokens.GetNextToken() ) ); |
|||
m_routerSettings->SetFixAllSegments( wxAtoi( tokens.GetNextToken() ) ); |
|||
m_routerSettings->SetCornerMode( |
|||
(DIRECTION_45::CORNER_MODE) wxAtoi( tokens.GetNextToken() ) ); |
|||
} |
|||
} |
|||
|
|||
fclose( f ); |
|||
|
|||
try |
|||
{ |
|||
PCB_PLUGIN io; |
|||
m_board.reset( io.Load( boardName.c_str(), nullptr, nullptr ) ); |
|||
|
|||
std::shared_ptr<DRC_ENGINE> drcEngine( new DRC_ENGINE ); |
|||
|
|||
CONSOLE_LOG consoleLog; |
|||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); |
|||
|
|||
bds.m_DRCEngine = drcEngine; |
|||
|
|||
drcEngine->SetBoard( m_board.get() ); |
|||
drcEngine->SetDesignSettings( &bds ); |
|||
drcEngine->SetLogReporter( new CONSOLE_MSG_REPORTER( &consoleLog ) ); |
|||
drcEngine->InitEngine( wxFileName() ); |
|||
} |
|||
catch( const PARSE_ERROR& parse_error ) |
|||
{ |
|||
printf( "parse error : %s (%s)\n", (const char*) parse_error.Problem().c_str(), |
|||
(const char*) parse_error.What().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
PNS_TEST_ENVIRONMENT::PNS_TEST_ENVIRONMENT() |
|||
{ |
|||
} |
|||
|
|||
|
|||
PNS_TEST_ENVIRONMENT::~PNS_TEST_ENVIRONMENT() |
|||
{ |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_ENVIRONMENT::SetMode( PNS::ROUTER_MODE mode ) |
|||
{ |
|||
m_mode = mode; |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_ENVIRONMENT::createRouter() |
|||
{ |
|||
m_iface.reset( new PNS_KICAD_IFACE_BASE ); |
|||
m_router.reset( new ROUTER ); |
|||
m_iface->SetBoard( m_board.get() ); |
|||
m_router->SetInterface( m_iface.get() ); |
|||
m_router->ClearWorld(); |
|||
m_router->SetMode( m_mode ); |
|||
m_router->SyncWorld(); |
|||
m_router->LoadSettings( new PNS::ROUTING_SETTINGS( nullptr, "" ) ); |
|||
m_router->Settings().SetMode( PNS::RM_Walkaround ); |
|||
m_router->Sizes().SetTrackWidth( 250000 ); |
|||
|
|||
//m_router->Settings().SetOptimizeDraggedTrack( true );
|
|||
|
|||
m_debugDecorator.Clear(); |
|||
m_iface->SetDebugDecorator( &m_debugDecorator ); |
|||
} |
|||
|
|||
void PNS_TEST_ENVIRONMENT::ReplayLog ( PNS_LOG_FILE* aLog, int aStartEventIndex, int aFrom, |
|||
int aTo ) |
|||
{ |
|||
|
|||
m_board = aLog->GetBoard(); |
|||
|
|||
createRouter(); |
|||
|
|||
m_router->LoadSettings( aLog->GetRoutingSettings() ); |
|||
|
|||
printf("Router mode: %d\n", m_router->Settings().Mode() ); |
|||
|
|||
for( auto evt : aLog->Events() ) |
|||
{ |
|||
auto item = aLog->ItemById(evt); |
|||
ITEM* ritem = item ? m_router->GetWorld()->FindItemByParent( item ) : nullptr; |
|||
|
|||
switch(evt.type) |
|||
{ |
|||
case LOGGER::EVT_START_ROUTE: |
|||
{ |
|||
m_debugDecorator.NewStage( "route-start", 0, PNSLOGINFO ); |
|||
m_debugDecorator.Message( wxString::Format( "route-start (%d, %d)", evt.p.x, evt.p.y ) ); |
|||
printf( " rtr start-route (%d, %d) %p \n", evt.p.x, evt.p.y, ritem ); |
|||
m_router->StartRouting( evt.p, ritem, ritem ? ritem->Layers().Start() : F_Cu ); |
|||
break; |
|||
} |
|||
|
|||
case LOGGER::EVT_START_DRAG: |
|||
{ |
|||
m_debugDecorator.NewStage( "drag-start", 0, PNSLOGINFO ); |
|||
m_debugDecorator.Message( wxString::Format( "drag-start (%d, %d)", evt.p.x, evt.p.y ) ); |
|||
bool rv = m_router->StartDragging( evt.p, ritem, 0 ); |
|||
printf( " rtr start-drag (%d, %d) %p ret %d\n", evt.p.x, evt.p.y, ritem, rv ? 1 : 0 ); |
|||
break; |
|||
} |
|||
|
|||
case LOGGER::EVT_FIX: |
|||
{ |
|||
m_debugDecorator.NewStage( "fix", 0, PNSLOGINFO ); |
|||
m_debugDecorator.Message( wxString::Format( "fix (%d, %d)", evt.p.x, evt.p.y ) ); |
|||
bool rv = m_router->FixRoute( evt.p, ritem ); |
|||
printf( " fix -> (%d, %d) ret %d\n", evt.p.x, evt.p.y, rv ? 1 : 0 ); |
|||
break; |
|||
} |
|||
|
|||
case LOGGER::EVT_MOVE: |
|||
{ |
|||
m_debugDecorator.NewStage( "move", 0, PNSLOGINFO ); |
|||
m_debugDecorator.Message( wxString::Format( "move (%d, %d)", evt.p.x, evt.p.y ) ); |
|||
printf( " move -> (%d, %d)\n", evt.p.x, evt.p.y ); |
|||
m_router->Move( evt.p, ritem ); |
|||
break; |
|||
} |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
PNS::NODE* node = nullptr; |
|||
|
|||
if( m_router->GetState() == PNS::ROUTER::ROUTE_TRACK ) |
|||
{ |
|||
#if 1
|
|||
m_debugDecorator.BeginGroup( "current route", PNSLOGINFO ); |
|||
|
|||
auto traces = m_router->Placer()->Traces(); |
|||
|
|||
for( const auto& t : traces.CItems() ) |
|||
{ |
|||
const LINE *l = static_cast<LINE*>(t.item); |
|||
const auto& sh = l->CLine(); |
|||
|
|||
m_debugDecorator.AddLine( sh, YELLOW, l->Width(), "line seg", |
|||
PNSLOGINFO ); |
|||
} |
|||
|
|||
m_debugDecorator.EndGroup( PNSLOGINFO ); |
|||
#endif
|
|||
|
|||
node = m_router->Placer()->CurrentNode( true ); |
|||
} |
|||
else if( m_router->GetState() == PNS::ROUTER::DRAG_SEGMENT ) |
|||
{ |
|||
node = m_router->GetDragger()->CurrentNode(); |
|||
} |
|||
|
|||
if( !node ) |
|||
return; |
|||
|
|||
NODE::ITEM_VECTOR removed, added; |
|||
|
|||
node->GetUpdatedItems( removed, added ); |
|||
|
|||
#if 1
|
|||
if( ! added.empty() ) |
|||
{ |
|||
bool first = true; |
|||
m_debugDecorator.BeginGroup( "node-added-items", PNSLOGINFO ); |
|||
|
|||
for( auto t : added ) |
|||
{ |
|||
if( t->OfKind( PNS::ITEM::SEGMENT_T ) ) |
|||
{ |
|||
auto s = static_cast<PNS::SEGMENT*>( t ); |
|||
m_debugDecorator.AddLine( SHAPE_LINE_CHAIN( { s->Seg().A, s->Seg().B } ), |
|||
MAGENTA, s->Width(), "seg", |
|||
PNSLOGINFO ); |
|||
first = false; |
|||
} |
|||
else if( t->OfKind( PNS::ITEM::ARC_T ) ) |
|||
{ |
|||
PNS::ARC* arc = static_cast<PNS::ARC*>( t ); |
|||
m_debugDecorator.AddLine( SHAPE_LINE_CHAIN( arc->Arc() ), MAGENTA, |
|||
arc->Width(), "arc", PNSLOGINFO ); |
|||
first = false; |
|||
} |
|||
} |
|||
|
|||
m_debugDecorator.EndGroup( PNSLOGINFO ); |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|||
|
|||
|
|||
PNS_TEST_DEBUG_DECORATOR::STAGE* PNS_TEST_DEBUG_DECORATOR::currentStage() |
|||
{ |
|||
if( m_stages.empty() ) |
|||
m_stages.push_back( new STAGE() ); |
|||
|
|||
return m_stages.back(); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::BeginGroup( const std::string& name, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
STAGE* st = currentStage(); |
|||
DEBUG_ENT *ent = new DEBUG_ENT(); |
|||
|
|||
ent->m_name = name; |
|||
ent->m_iter = m_iter; |
|||
|
|||
if( m_activeEntry ) |
|||
{ |
|||
m_activeEntry->AddChild( ent ); |
|||
} |
|||
|
|||
printf( "LOG BeginGroup %s %p\n", name.c_str(), ent ); |
|||
|
|||
m_activeEntry = ent; |
|||
m_grouping = true; |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::EndGroup( const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
printf( "LOG EndGroup\n" ); |
|||
|
|||
if( !m_activeEntry ) |
|||
return; |
|||
|
|||
m_activeEntry = m_activeEntry->m_parent; |
|||
|
|||
if( !m_activeEntry ) |
|||
m_grouping = false; |
|||
} |
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::addEntry( DEBUG_ENT* ent ) |
|||
{ |
|||
auto st = currentStage(); |
|||
m_activeEntry->AddChild( ent ); |
|||
} |
|||
|
|||
|
|||
/* virtual void AddLine( const SHAPE_LINE_CHAIN& aLine, const KIGFX::COLOR4D& aColor,
|
|||
int aWidth, const std::string aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void AddSegment( SEG aS, const KIGFX::COLOR4D& aColor, |
|||
const std::string aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void AddBox( BOX2I aB, const KIGFX::COLOR4D& aColor, |
|||
const std::string aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
*/ |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::AddPoint( const VECTOR2I& aP, const KIGFX::COLOR4D& aColor, |
|||
int aSize, const std::string& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
auto sh = new SHAPE_LINE_CHAIN; |
|||
|
|||
sh->Append( aP.x - aSize, aP.y - aSize ); |
|||
sh->Append( aP.x + aSize, aP.y + aSize ); |
|||
sh->Append( aP.x, aP.y ); |
|||
sh->Append( aP.x - aSize, aP.y + aSize ); |
|||
sh->Append( aP.x + aSize, aP.y - aSize ); |
|||
|
|||
DEBUG_ENT* ent = new DEBUG_ENT(); |
|||
|
|||
ent->m_shapes.push_back( sh ); |
|||
ent->m_color = aColor; |
|||
ent->m_width = 30000; |
|||
ent->m_iter = m_iter; |
|||
ent->m_name = aName; |
|||
ent->m_hasLabels = false; |
|||
ent->m_srcLoc = aSrcLoc; |
|||
|
|||
addEntry( ent ); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::AddLine( const SHAPE_LINE_CHAIN& aLine, const KIGFX::COLOR4D& aColor, |
|||
int aWidth, const std::string& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
auto sh = new SHAPE_LINE_CHAIN( aLine ); |
|||
DEBUG_ENT* ent = new DEBUG_ENT(); |
|||
|
|||
ent->m_shapes.push_back( sh ); |
|||
ent->m_color = aColor; |
|||
ent->m_width = aWidth; |
|||
ent->m_name = aName; |
|||
ent->m_iter = m_iter; |
|||
ent->m_srcLoc = aSrcLoc; |
|||
|
|||
addEntry( ent ); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::AddSegment( const SEG& aS, const KIGFX::COLOR4D& aColor, |
|||
const std::string& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
auto sh = new SHAPE_LINE_CHAIN( { aS.A, aS.B } ); |
|||
DEBUG_ENT* ent = new DEBUG_ENT(); |
|||
|
|||
ent->m_shapes.push_back( sh ); |
|||
ent->m_color = aColor; |
|||
ent->m_width = 10000; |
|||
ent->m_name = aName; |
|||
ent->m_iter = m_iter; |
|||
ent->m_srcLoc = aSrcLoc; |
|||
|
|||
addEntry( ent ); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::AddBox( const BOX2I& aB, const KIGFX::COLOR4D& aColor, |
|||
const std::string& aName, const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
auto sh = new SHAPE_RECT( aB.GetPosition(), aB.GetWidth(), aB.GetHeight() ); |
|||
DEBUG_ENT* ent = new DEBUG_ENT(); |
|||
|
|||
ent->m_shapes.push_back( sh ); |
|||
ent->m_color = aColor; |
|||
ent->m_width = 10000; |
|||
ent->m_name = aName; |
|||
ent->m_iter = m_iter; |
|||
ent->m_srcLoc = aSrcLoc; |
|||
addEntry( ent ); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::Message( const wxString& msg, const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
DEBUG_ENT* ent = new DEBUG_ENT(); |
|||
ent->m_msg = msg.c_str(); |
|||
ent->m_srcLoc = aSrcLoc; |
|||
addEntry( ent ); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::NewStage( const std::string& name, int iter, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
STAGE* stage = new STAGE(); |
|||
stage->m_name = name; |
|||
stage->m_iter = iter; |
|||
|
|||
m_stages.push_back( new STAGE); |
|||
m_activeEntry = m_stages.back()->m_entries; |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::DEBUG_ENT::IterateTree( |
|||
std::function<bool( PNS_TEST_DEBUG_DECORATOR::DEBUG_ENT* )> visitor, int depth ) |
|||
{ |
|||
if( !visitor( this ) ) |
|||
return; |
|||
|
|||
|
|||
for( auto child : m_children ) |
|||
{ |
|||
child->IterateTree( visitor, depth + 1 ); |
|||
} |
|||
} |
|||
|
|||
|
|||
BOX2I PNS_TEST_DEBUG_DECORATOR::GetStageExtents( int stage ) const |
|||
{ |
|||
STAGE* st = m_stages[stage]; |
|||
BOX2I bb; |
|||
bool first = true; |
|||
|
|||
auto visitor = [&]( DEBUG_ENT* ent ) -> bool { |
|||
for( auto sh : ent->m_shapes ) |
|||
{ |
|||
if( first ) |
|||
bb = sh->BBox(); |
|||
else |
|||
bb.Merge( sh->BBox() ); |
|||
|
|||
first = false; |
|||
} |
|||
|
|||
return true; |
|||
}; |
|||
|
|||
return bb; |
|||
} |
@ -1,280 +0,0 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020-2021 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 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 __PNS_LOG_H |
|||
#define __PNS_LOG_H |
|||
|
|||
#include <cstdio> |
|||
|
|||
#include <wx/tokenzr.h> |
|||
|
|||
#include <geometry/shape.h> |
|||
#include <geometry/shape_circle.h> |
|||
#include <geometry/shape_file_io.h> |
|||
#include <geometry/shape_line_chain.h> |
|||
#include <geometry/shape_rect.h> |
|||
|
|||
#include <router/pns_debug_decorator.h> |
|||
#include <router/pns_item.h> |
|||
#include <router/pns_line.h> |
|||
#include <router/pns_line_placer.h> |
|||
#include <router/pns_dragger.h> |
|||
#include <router/pns_logger.h> |
|||
#include <router/pns_node.h> |
|||
#include <router/pns_router.h> |
|||
#include <router/pns_solid.h> |
|||
#include <router/pns_routing_settings.h> |
|||
|
|||
#include <pcb_shape.h> |
|||
#include <pcb_text.h> |
|||
#include <pcbnew/zone.h> |
|||
|
|||
#include <router/pns_kicad_iface.h> |
|||
|
|||
#include <pcbnew/board.h> |
|||
|
|||
#include <pcbnew/plugins/kicad/pcb_plugin.h> |
|||
#include <pcbnew/plugins/kicad/pcb_parser.h> |
|||
|
|||
#include <wx/treelist.h> |
|||
|
|||
class PNS_LOG_FILE |
|||
{ |
|||
public: |
|||
PNS_LOG_FILE(); |
|||
~PNS_LOG_FILE() {} |
|||
|
|||
struct EVENT_ENTRY |
|||
{ |
|||
VECTOR2I p; |
|||
PNS::LOGGER::EVENT_TYPE type; |
|||
const PNS::ITEM* item; |
|||
KIID uuid; |
|||
}; |
|||
|
|||
// loads a board file and associated P&s event log |
|||
bool Load( const std::string& logName, const std::string boardName ); |
|||
|
|||
BOARD_CONNECTED_ITEM* ItemById( const EVENT_ENTRY& evt ) |
|||
{ |
|||
BOARD_CONNECTED_ITEM* parent = nullptr; |
|||
|
|||
for( auto item : m_board->AllConnectedItems() ) |
|||
{ |
|||
if( item->m_Uuid == evt.uuid ) |
|||
{ |
|||
parent = item; |
|||
break; |
|||
}; |
|||
} |
|||
|
|||
return parent; |
|||
} |
|||
|
|||
std::vector<EVENT_ENTRY>& Events() { return m_events; } |
|||
|
|||
std::shared_ptr<BOARD> GetBoard() const { return m_board; } |
|||
|
|||
void SetBoard( std::shared_ptr<BOARD> brd ) { m_board = brd; } |
|||
|
|||
PNS::ROUTING_SETTINGS* GetRoutingSettings() const { return m_routerSettings.get(); } |
|||
|
|||
private: |
|||
std::unique_ptr<PNS::ROUTING_SETTINGS> m_routerSettings; |
|||
std::vector<EVENT_ENTRY> m_events; |
|||
std::shared_ptr<BOARD> m_board; |
|||
}; |
|||
|
|||
|
|||
class PNS_TEST_DEBUG_DECORATOR : public PNS::DEBUG_DECORATOR |
|||
{ |
|||
public: |
|||
|
|||
struct DEBUG_ENT |
|||
{ |
|||
DEBUG_ENT( DEBUG_ENT* aParent = nullptr ) |
|||
{ |
|||
m_iter = 0; |
|||
m_color = KIGFX::COLOR4D::WHITE; |
|||
m_width = 10000; |
|||
m_name = "<unknown>"; |
|||
m_parent = aParent; |
|||
m_visible = true; |
|||
m_selected = false; |
|||
} |
|||
|
|||
~DEBUG_ENT() |
|||
{ |
|||
for( auto s : m_shapes ) |
|||
{ |
|||
delete s; |
|||
} |
|||
|
|||
for( auto ch : m_children ) |
|||
{ |
|||
delete ch; |
|||
} |
|||
} |
|||
|
|||
DEBUG_ENT* NewChild() |
|||
{ |
|||
DEBUG_ENT* ent = new DEBUG_ENT( this ); |
|||
m_children.push_back( ent ); |
|||
|
|||
return ent; |
|||
} |
|||
|
|||
void AddChild( DEBUG_ENT* ent ) |
|||
{ |
|||
ent->m_parent = this; |
|||
m_children.push_back( ent ); |
|||
} |
|||
|
|||
bool IsVisible() const |
|||
{ |
|||
if ( m_visible ) |
|||
return true; |
|||
|
|||
auto parent = m_parent; |
|||
|
|||
while(parent) |
|||
{ |
|||
if(parent->m_visible) |
|||
return true; |
|||
|
|||
parent = parent->m_parent; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
void IterateTree( std::function<bool(DEBUG_ENT*)> visitor, int depth=0 ); |
|||
|
|||
DEBUG_ENT* m_parent; |
|||
std::vector<SHAPE*> m_shapes; |
|||
std::vector<DEBUG_ENT*> m_children; |
|||
KIGFX::COLOR4D m_color; |
|||
int m_width; |
|||
bool m_hasLabels = true; |
|||
int m_iter; |
|||
std::string m_name; |
|||
std::string m_msg; |
|||
PNS::DEBUG_DECORATOR::SRC_LOCATION_INFO m_srcLoc; |
|||
bool m_visible; |
|||
bool m_selected; |
|||
}; |
|||
|
|||
struct STAGE |
|||
{ |
|||
STAGE() |
|||
{ |
|||
m_name = "<unknown>"; |
|||
m_iter = 0; |
|||
m_entries = new DEBUG_ENT(); |
|||
} |
|||
|
|||
~STAGE() |
|||
{ |
|||
} |
|||
|
|||
std::string m_name; |
|||
int m_iter; |
|||
DEBUG_ENT* m_entries; |
|||
}; |
|||
|
|||
PNS_TEST_DEBUG_DECORATOR() |
|||
{ |
|||
m_iter = 0; |
|||
m_grouping = false; |
|||
m_activeEntry = nullptr; |
|||
SetDebugEnabled( true ); |
|||
} |
|||
|
|||
virtual ~PNS_TEST_DEBUG_DECORATOR() |
|||
{ |
|||
// fixme: I know it's a hacky tool but it should clean after itself at some point... |
|||
|
|||
} |
|||
|
|||
virtual void SetIteration( int iter ) override { m_iter = iter; } |
|||
|
|||
virtual void Message( const wxString& msg, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void NewStage( const std::string& name, int iter, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void BeginGroup( const std::string& name, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void EndGroup( const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void AddPoint( const VECTOR2I& aP, const KIGFX::COLOR4D& aColor, int aSize, |
|||
const std::string& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void AddLine( const SHAPE_LINE_CHAIN& aLine, const KIGFX::COLOR4D& aColor, |
|||
int aWidth, const std::string& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void AddSegment( const SEG& aS, const KIGFX::COLOR4D& aColor, |
|||
const std::string& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void AddBox( const BOX2I& aB, const KIGFX::COLOR4D& aColor, |
|||
const std::string& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void Clear() override {}; |
|||
|
|||
int GetStageCount() const { return m_stages.size(); } |
|||
|
|||
STAGE* GetStage( int index ) { return m_stages[index]; } |
|||
|
|||
BOX2I GetStageExtents( int stage ) const; |
|||
|
|||
private: |
|||
void addEntry( DEBUG_ENT* ent ); |
|||
|
|||
bool m_grouping; |
|||
DEBUG_ENT* m_activeEntry; |
|||
STAGE* currentStage(); |
|||
int m_iter; |
|||
std::vector<STAGE*> m_stages; |
|||
}; |
|||
|
|||
|
|||
class PNS_TEST_ENVIRONMENT |
|||
{ |
|||
public: |
|||
PNS_TEST_ENVIRONMENT(); |
|||
~PNS_TEST_ENVIRONMENT(); |
|||
|
|||
void SetMode( PNS::ROUTER_MODE mode ); |
|||
void ReplayLog( PNS_LOG_FILE* aLog, int aStartEventIndex = 0, int aFrom = 0, int aTo = -1 ); |
|||
|
|||
PNS_TEST_DEBUG_DECORATOR* GetDebugDecorator() { return &m_debugDecorator; }; |
|||
|
|||
private: |
|||
void createRouter(); |
|||
|
|||
PNS::ROUTER_MODE m_mode; |
|||
PNS_TEST_DEBUG_DECORATOR m_debugDecorator; |
|||
std::shared_ptr<BOARD> m_board; |
|||
std::unique_ptr<PNS_KICAD_IFACE_BASE> m_iface; |
|||
std::unique_ptr<PNS::ROUTER> m_router; |
|||
}; |
|||
|
|||
|
|||
#endif |
@ -0,0 +1,130 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020-2022 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 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 |
|||
*/ |
|||
|
|||
|
|||
// WARNING - this Tom's crappy PNS hack tool code. Please don't complain about its quality
|
|||
// (unless you want to improve it).
|
|||
|
|||
#include "pns_log_file.h"
|
|||
|
|||
#include <board_design_settings.h>
|
|||
|
|||
#include <pcbnew/plugins/kicad/pcb_plugin.h>
|
|||
#include <pcbnew/drc/drc_engine.h>
|
|||
|
|||
#include <console_log.h>
|
|||
|
|||
BOARD_CONNECTED_ITEM* PNS_LOG_FILE::ItemById( const PNS_LOG_FILE::EVENT_ENTRY& evt ) |
|||
{ |
|||
BOARD_CONNECTED_ITEM* parent = nullptr; |
|||
|
|||
for( auto item : m_board->AllConnectedItems() ) |
|||
{ |
|||
if( item->m_Uuid == evt.uuid ) |
|||
{ |
|||
parent = item; |
|||
break; |
|||
}; |
|||
} |
|||
|
|||
return parent; |
|||
} |
|||
|
|||
static const wxString readLine( FILE* f ) |
|||
{ |
|||
char str[16384]; |
|||
fgets( str, sizeof( str ) - 1, f ); |
|||
return wxString( str ); |
|||
} |
|||
|
|||
|
|||
PNS_LOG_FILE::PNS_LOG_FILE() |
|||
{ |
|||
m_routerSettings.reset( new PNS::ROUTING_SETTINGS( nullptr, "" ) ); |
|||
} |
|||
|
|||
|
|||
bool PNS_LOG_FILE::Load( const std::string& logName, const std::string boardName ) |
|||
{ |
|||
FILE* f = fopen( logName.c_str(), "rb" ); |
|||
|
|||
if( !f ) |
|||
return false; |
|||
|
|||
while( !feof( f ) ) |
|||
{ |
|||
wxStringTokenizer tokens( readLine( f ) ); |
|||
|
|||
if( !tokens.CountTokens() ) |
|||
continue; |
|||
|
|||
wxString cmd = tokens.GetNextToken(); |
|||
|
|||
if( cmd == "event" ) |
|||
{ |
|||
EVENT_ENTRY evt; |
|||
evt.p.x = wxAtoi( tokens.GetNextToken() ); |
|||
evt.p.y = wxAtoi( tokens.GetNextToken() ); |
|||
evt.type = (PNS::LOGGER::EVENT_TYPE) wxAtoi( tokens.GetNextToken() ); |
|||
evt.uuid = KIID( tokens.GetNextToken() ); |
|||
m_events.push_back( evt ); |
|||
} |
|||
else if( cmd == "config" ) |
|||
{ |
|||
m_routerSettings->SetMode( (PNS::PNS_MODE) wxAtoi( tokens.GetNextToken() ) ); |
|||
m_routerSettings->SetRemoveLoops( wxAtoi( tokens.GetNextToken() ) ); |
|||
m_routerSettings->SetFixAllSegments( wxAtoi( tokens.GetNextToken() ) ); |
|||
m_routerSettings->SetCornerMode( |
|||
(DIRECTION_45::CORNER_MODE) wxAtoi( tokens.GetNextToken() ) ); |
|||
} |
|||
} |
|||
|
|||
fclose( f ); |
|||
|
|||
try |
|||
{ |
|||
PCB_PLUGIN io; |
|||
m_board.reset( io.Load( boardName.c_str(), nullptr, nullptr ) ); |
|||
|
|||
std::shared_ptr<DRC_ENGINE> drcEngine( new DRC_ENGINE ); |
|||
|
|||
CONSOLE_LOG consoleLog; |
|||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); |
|||
|
|||
bds.m_DRCEngine = drcEngine; |
|||
|
|||
drcEngine->SetBoard( m_board.get() ); |
|||
drcEngine->SetDesignSettings( &bds ); |
|||
drcEngine->SetLogReporter( new CONSOLE_MSG_REPORTER( &consoleLog ) ); |
|||
drcEngine->InitEngine( wxFileName() ); |
|||
} |
|||
catch( const PARSE_ERROR& parse_error ) |
|||
{ |
|||
printf( "parse error : %s (%s)\n", (const char*) parse_error.Problem().c_str(), |
|||
(const char*) parse_error.What().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
@ -0,0 +1,75 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020-2022 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 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 |
|||
*/ |
|||
|
|||
|
|||
// WARNING - this Tom's crappy PNS hack tool code. Please don't complain about its quality |
|||
// (unless you want to improve it). |
|||
|
|||
#ifndef __PNS_LOG_FILE_H |
|||
#define __PNS_LOG_FILE_H |
|||
|
|||
#include <memory> |
|||
#include <vector> |
|||
|
|||
#include <kiid.h> |
|||
#include <math/vector2d.h> |
|||
#include <router/pns_logger.h> |
|||
#include <router/pns_item.h> |
|||
#include <router/pns_routing_settings.h> |
|||
|
|||
#include <pcbnew/board.h> |
|||
#include <pcbnew/board_connected_item.h> |
|||
|
|||
class PNS_LOG_FILE |
|||
{ |
|||
public: |
|||
PNS_LOG_FILE(); |
|||
~PNS_LOG_FILE() {} |
|||
|
|||
struct EVENT_ENTRY |
|||
{ |
|||
VECTOR2I p; |
|||
PNS::LOGGER::EVENT_TYPE type; |
|||
const PNS::ITEM* item; |
|||
KIID uuid; |
|||
}; |
|||
|
|||
// Loads a P&S event log and the associated board file. These two always go together. |
|||
bool Load( const std::string& logFileName, const std::string boardFileName ); |
|||
|
|||
BOARD_CONNECTED_ITEM* ItemById( const EVENT_ENTRY& evt ); |
|||
|
|||
std::vector<EVENT_ENTRY>& Events() { return m_events; } |
|||
|
|||
void SetBoard( std::shared_ptr<BOARD> brd ) { m_board = brd; } |
|||
std::shared_ptr<BOARD> GetBoard() const { return m_board; } |
|||
|
|||
PNS::ROUTING_SETTINGS* GetRoutingSettings() const { return m_routerSettings.get(); } |
|||
|
|||
private: |
|||
std::unique_ptr<PNS::ROUTING_SETTINGS> m_routerSettings; |
|||
std::vector<EVENT_ENTRY> m_events; |
|||
std::shared_ptr<BOARD> m_board; |
|||
}; |
|||
|
|||
#endif |
@ -0,0 +1,255 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020-2021 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 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 "pns_test_debug_decorator.h"
|
|||
#include "pns_log_file.h"
|
|||
#include "pns_log_player.h"
|
|||
|
|||
#if 0
|
|||
#include <qa/drc_proto/drc_proto.h>
|
|||
|
|||
#include <board_design_settings.h>
|
|||
#include <pcbnew/drc/drc_engine.h>
|
|||
#include <pcbnew/drc/drc_test_provider.h>
|
|||
#include <pns_arc.h>
|
|||
#endif
|
|||
|
|||
#define PNSLOGINFO PNS::DEBUG_DECORATOR::SRC_LOCATION_INFO( __FILE__, __FUNCTION__, __LINE__ )
|
|||
|
|||
using namespace PNS; |
|||
|
|||
PNS_LOG_PLAYER::PNS_LOG_PLAYER() |
|||
{ |
|||
} |
|||
|
|||
|
|||
PNS_LOG_PLAYER::~PNS_LOG_PLAYER() |
|||
{ |
|||
if( m_debugDecorator ) |
|||
delete m_debugDecorator; |
|||
} |
|||
|
|||
void PNS_LOG_PLAYER::SetMode( PNS::ROUTER_MODE mode ) |
|||
{ |
|||
m_mode = mode; |
|||
} |
|||
|
|||
void PNS_LOG_PLAYER::createRouter() |
|||
{ |
|||
m_viewTracker.reset( new PNS_LOG_VIEW_TRACKER ); |
|||
m_iface.reset( new PNS_LOG_PLAYER_KICAD_IFACE( m_viewTracker.get() ) ); |
|||
m_router.reset( new ROUTER ); |
|||
m_iface->SetBoard( m_board.get() ); |
|||
m_router->SetInterface( m_iface.get() ); |
|||
m_router->ClearWorld(); |
|||
m_router->SetMode( m_mode ); |
|||
m_router->SyncWorld(); |
|||
m_router->LoadSettings( new PNS::ROUTING_SETTINGS( nullptr, "" ) ); |
|||
m_router->Settings().SetMode( PNS::RM_Walkaround ); |
|||
m_router->Sizes().SetTrackWidth( 250000 ); |
|||
|
|||
//m_router->Settings().SetOptimizeDraggedTrack( true );
|
|||
|
|||
m_debugDecorator = new PNS_TEST_DEBUG_DECORATOR; |
|||
m_debugDecorator->Clear(); |
|||
m_iface->SetDebugDecorator( m_debugDecorator ); |
|||
} |
|||
|
|||
void PNS_LOG_PLAYER::ReplayLog( PNS_LOG_FILE* aLog, int aStartEventIndex, int aFrom, int aTo ) |
|||
{ |
|||
m_board = aLog->GetBoard(); |
|||
|
|||
createRouter(); |
|||
|
|||
m_router->LoadSettings( aLog->GetRoutingSettings() ); |
|||
|
|||
printf( "Router mode: %d\n", m_router->Settings().Mode() ); |
|||
|
|||
int eventIdx = 0; |
|||
|
|||
for( auto evt : aLog->Events() ) |
|||
{ |
|||
if( eventIdx < aFrom || ( aTo >= 0 && eventIdx > aTo ) ) |
|||
continue; |
|||
|
|||
auto item = aLog->ItemById( evt ); |
|||
ITEM* ritem = item ? m_router->GetWorld()->FindItemByParent( item ) : nullptr; |
|||
|
|||
eventIdx++; |
|||
|
|||
switch( evt.type ) |
|||
{ |
|||
case LOGGER::EVT_START_ROUTE: |
|||
{ |
|||
m_debugDecorator->NewStage( "route-start", 0, PNSLOGINFO ); |
|||
m_viewTracker->SetStage( m_debugDecorator->GetStageCount() - 1 ); |
|||
m_debugDecorator->Message( |
|||
wxString::Format( "route-start (%d, %d)", evt.p.x, evt.p.y ) ); |
|||
printf( " rtr start-route (%d, %d) %p \n", evt.p.x, evt.p.y, ritem ); |
|||
m_router->StartRouting( evt.p, ritem, ritem ? ritem->Layers().Start() : F_Cu ); |
|||
break; |
|||
} |
|||
|
|||
case LOGGER::EVT_START_DRAG: |
|||
{ |
|||
m_debugDecorator->NewStage( "drag-start", 0, PNSLOGINFO ); |
|||
m_viewTracker->SetStage( m_debugDecorator->GetStageCount() - 1 ); |
|||
m_debugDecorator->Message( |
|||
wxString::Format( "drag-start (%d, %d)", evt.p.x, evt.p.y ) ); |
|||
bool rv = m_router->StartDragging( evt.p, ritem, 0 ); |
|||
printf( " rtr start-drag (%d, %d) %p ret %d\n", evt.p.x, evt.p.y, ritem, rv ? 1 : 0 ); |
|||
break; |
|||
} |
|||
|
|||
case LOGGER::EVT_FIX: |
|||
{ |
|||
m_debugDecorator->NewStage( "fix", 0, PNSLOGINFO ); |
|||
m_viewTracker->SetStage( m_debugDecorator->GetStageCount() - 1 ); |
|||
m_debugDecorator->Message( wxString::Format( "fix (%d, %d)", evt.p.x, evt.p.y ) ); |
|||
bool rv = m_router->FixRoute( evt.p, ritem ); |
|||
printf( " fix -> (%d, %d) ret %d\n", evt.p.x, evt.p.y, rv ? 1 : 0 ); |
|||
break; |
|||
} |
|||
|
|||
case LOGGER::EVT_MOVE: |
|||
{ |
|||
m_debugDecorator->NewStage( "move", 0, PNSLOGINFO ); |
|||
m_viewTracker->SetStage( m_debugDecorator->GetStageCount() - 1 ); |
|||
m_debugDecorator->Message( wxString::Format( "move (%d, %d)", evt.p.x, evt.p.y ) ); |
|||
printf( " move -> (%d, %d)\n", evt.p.x, evt.p.y ); |
|||
m_router->Move( evt.p, ritem ); |
|||
break; |
|||
} |
|||
|
|||
case LOGGER::EVT_TOGGLE_VIA: |
|||
{ |
|||
m_debugDecorator->NewStage( "toggle-via", 0, PNSLOGINFO ); |
|||
m_viewTracker->SetStage( m_debugDecorator->GetStageCount() - 1 ); |
|||
m_router->ToggleViaPlacement(); |
|||
break; |
|||
} |
|||
|
|||
default: break; |
|||
} |
|||
|
|||
PNS::NODE* node = nullptr; |
|||
|
|||
#if 0
|
|||
if( m_router->GetState() == PNS::ROUTER::ROUTE_TRACK ) |
|||
{ |
|||
m_debugDecorator->BeginGroup( "current route", 0 ); |
|||
|
|||
auto traces = m_router->Placer()->Traces(); |
|||
|
|||
for( const auto& t : traces.CItems() ) |
|||
{ |
|||
const LINE *l = static_cast<LINE*>(t.item); |
|||
const auto& sh = l->CLine(); |
|||
|
|||
m_debugDecorator->AddItem( l, YELLOW, 0, wxT( "line seg" ) ); |
|||
} |
|||
|
|||
m_debugDecorator->EndGroup( PNSLOGINFO ); |
|||
|
|||
node = m_router->Placer()->CurrentNode( true ); |
|||
} |
|||
else if( m_router->GetState() == PNS::ROUTER::DRAG_SEGMENT ) |
|||
{ |
|||
node = m_router->GetDragger()->CurrentNode(); |
|||
} |
|||
if( !node ) |
|||
return; |
|||
|
|||
NODE::ITEM_VECTOR removed, added; |
|||
|
|||
node->GetUpdatedItems( removed, added ); |
|||
|
|||
if( ! added.empty() ) |
|||
{ |
|||
bool first = true; |
|||
m_debugDecorator->BeginGroup( wxT( "node-added-items" ), 0 ); |
|||
|
|||
for( auto t : added ) |
|||
{ |
|||
m_debugDecorator->AddItem( t, MAGENTA, 0, wxT( "seg" ) ); |
|||
} |
|||
|
|||
m_debugDecorator->EndGroup(); |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|||
|
|||
|
|||
PNS_LOG_PLAYER_KICAD_IFACE::PNS_LOG_PLAYER_KICAD_IFACE( PNS_LOG_VIEW_TRACKER* aViewTracker ) : |
|||
m_viewTracker( aViewTracker ) |
|||
{ |
|||
} |
|||
|
|||
PNS_LOG_PLAYER_KICAD_IFACE::~PNS_LOG_PLAYER_KICAD_IFACE() |
|||
{ |
|||
} |
|||
|
|||
void PNS_LOG_PLAYER_KICAD_IFACE::HideItem( PNS::ITEM* aItem ) |
|||
{ |
|||
//printf("DBG hide %p\n", aItem);
|
|||
m_viewTracker->HideItem( aItem ); |
|||
} |
|||
|
|||
void PNS_LOG_PLAYER_KICAD_IFACE::DisplayItem( const PNS::ITEM* aItem, int aClearance, bool aEdit ) |
|||
{ |
|||
//printf("DBG disp %p\n", aItem);
|
|||
m_viewTracker->DisplayItem( aItem ); |
|||
} |
|||
|
|||
|
|||
PNS_LOG_VIEW_TRACKER::PNS_LOG_VIEW_TRACKER() |
|||
{ |
|||
} |
|||
|
|||
PNS_LOG_VIEW_TRACKER::~PNS_LOG_VIEW_TRACKER() |
|||
{ |
|||
} |
|||
|
|||
void PNS_LOG_VIEW_TRACKER::SetStage( int aStage ) |
|||
{ |
|||
m_currentStage = aStage; |
|||
m_vitems[m_currentStage] = VIEW_ENTRIES(); |
|||
} |
|||
|
|||
void PNS_LOG_VIEW_TRACKER::HideItem( PNS::ITEM* aItem ) |
|||
{ |
|||
ENTRY ent; |
|||
ent.isHideOp = true; |
|||
ent.item = aItem; |
|||
m_vitems[m_currentStage].push_back( ent ); |
|||
} |
|||
|
|||
void PNS_LOG_VIEW_TRACKER::DisplayItem( const PNS::ITEM* aItem ) |
|||
{ |
|||
ENTRY ent; |
|||
ent.isHideOp = false; |
|||
ent.item = aItem->Clone(); |
|||
m_vitems[m_currentStage].push_back( ent ); |
|||
//printf("DBG disp cur %d cnt %d\n", m_currentStage, m_vitems[m_currentStage].size() );
|
|||
} |
@ -0,0 +1,100 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020-2021 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 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 __PNS_LOG_PLAYER_H |
|||
#define __PNS_LOG_PLAYER_H |
|||
|
|||
#include <map> |
|||
#include <pcbnew/board.h> |
|||
|
|||
#include <router/pns_routing_settings.h> |
|||
#include <router/pns_kicad_iface.h> |
|||
#include <router/pns_router.h> |
|||
|
|||
|
|||
class PNS_TEST_DEBUG_DECORATOR; |
|||
class PNS_LOG_FILE; |
|||
class PNS_LOG_PLAYER; |
|||
|
|||
class PNS_LOG_VIEW_TRACKER |
|||
{ |
|||
public: |
|||
struct ENTRY |
|||
{ |
|||
bool isHideOp; |
|||
const PNS::ITEM* item; |
|||
}; |
|||
|
|||
typedef std::vector<ENTRY> VIEW_ENTRIES; |
|||
|
|||
PNS_LOG_VIEW_TRACKER(); |
|||
~PNS_LOG_VIEW_TRACKER(); |
|||
|
|||
void SetStage( int aStage ); |
|||
VIEW_ENTRIES& GetEntriesForStage( int aStage ) { return m_vitems[aStage]; } |
|||
|
|||
void HideItem( PNS::ITEM* aItem ); |
|||
void DisplayItem( const PNS::ITEM* aItem ); |
|||
|
|||
|
|||
private: |
|||
int m_currentStage; |
|||
std::map<int, VIEW_ENTRIES> m_vitems; |
|||
}; |
|||
|
|||
class PNS_LOG_PLAYER_KICAD_IFACE : public PNS_KICAD_IFACE_BASE |
|||
{ |
|||
public: |
|||
PNS_LOG_PLAYER_KICAD_IFACE( PNS_LOG_VIEW_TRACKER* aViewTracker ); |
|||
~PNS_LOG_PLAYER_KICAD_IFACE(); |
|||
|
|||
void HideItem( PNS::ITEM* aItem ) override; |
|||
void DisplayItem( const PNS::ITEM* aItem, int aClearance, bool aEdit = false ) override; |
|||
|
|||
private: |
|||
PNS_LOG_VIEW_TRACKER *m_viewTracker; |
|||
}; |
|||
|
|||
|
|||
class PNS_LOG_PLAYER |
|||
{ |
|||
public: |
|||
PNS_LOG_PLAYER(); |
|||
~PNS_LOG_PLAYER(); |
|||
|
|||
void SetMode( PNS::ROUTER_MODE mode ); |
|||
void ReplayLog( PNS_LOG_FILE* aLog, int aStartEventIndex = 0, int aFrom = 0, int aTo = -1 ); |
|||
|
|||
PNS_TEST_DEBUG_DECORATOR* GetDebugDecorator() { return m_debugDecorator; }; |
|||
std::shared_ptr<PNS_LOG_VIEW_TRACKER> GetViewTracker() { return m_viewTracker; } |
|||
private: |
|||
void createRouter(); |
|||
|
|||
PNS::ROUTER_MODE m_mode; |
|||
std::shared_ptr<PNS_LOG_VIEW_TRACKER> m_viewTracker; |
|||
PNS_TEST_DEBUG_DECORATOR* m_debugDecorator; |
|||
std::shared_ptr<BOARD> m_board; |
|||
std::unique_ptr<PNS_LOG_PLAYER_KICAD_IFACE> m_iface; |
|||
std::unique_ptr<PNS::ROUTER> m_router; |
|||
}; |
|||
|
|||
#endif |
@ -0,0 +1,819 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020-2022 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 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 |
|||
*/ |
|||
|
|||
|
|||
// WARNING - this Tom's crappy PNS hack tool code. Please don't complain about its quality
|
|||
// (unless you want to improve it).
|
|||
|
|||
#include <wx/clipbrd.h>
|
|||
#include <pgm_base.h>
|
|||
#include <profile.h>
|
|||
#include <trace_helpers.h>
|
|||
#include <view/view_overlay.h>
|
|||
|
|||
|
|||
#include "label_manager.h"
|
|||
|
|||
#include "pns_log_file.h"
|
|||
#include "pns_log_player.h"
|
|||
#include "pns_log_viewer_frame.h"
|
|||
|
|||
#include "router/pns_diff_pair.h"
|
|||
#include "router/pns_utils.h"
|
|||
#include "router/router_preview_item.h"
|
|||
|
|||
|
|||
|
|||
class WX_SHAPE_TREE_ITEM_DATA : public wxClientData |
|||
{ |
|||
public: |
|||
WX_SHAPE_TREE_ITEM_DATA( PNS_DEBUG_SHAPE* item ) : m_item( item ){}; |
|||
|
|||
PNS_DEBUG_SHAPE* m_item; |
|||
}; |
|||
|
|||
|
|||
PNS_LOG_VIEWER_OVERLAY::PNS_LOG_VIEWER_OVERLAY( KIGFX::GAL* aGal ) |
|||
{ |
|||
m_labelMgr.reset( new LABEL_MANAGER( aGal ) ); |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_OVERLAY::AnnotatedPolyline( const SHAPE_LINE_CHAIN& aL, std::string name, |
|||
bool aShowVertexNumbers ) |
|||
{ |
|||
Polyline( aL ); |
|||
|
|||
if( aShowVertexNumbers) |
|||
m_labelMgr->Add( aL, GetStrokeColor() ); |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_OVERLAY::AnnotatedPoint( const VECTOR2I p, int size, std::string name, bool aShowVertexNumbers ) |
|||
{ |
|||
Line( p + VECTOR2D( size, size ), p - VECTOR2D( size, size ) ); |
|||
Line( p + VECTOR2D( -size, size ), p - VECTOR2D( -size, size ) ); |
|||
|
|||
//if( aShowVertexNumbers)
|
|||
// m_labelMgr->Add( aL, GetStrokeColor() );
|
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_OVERLAY::Arc( const SHAPE_ARC& arc ) |
|||
{ |
|||
double radius = arc.GetRadius(); |
|||
EDA_ANGLE start_angle = arc.GetStartAngle(); |
|||
EDA_ANGLE angle = arc.GetCentralAngle(); |
|||
|
|||
KIGFX::VIEW_OVERLAY::SetLineWidth( arc.GetWidth() / 10 ); |
|||
KIGFX::VIEW_OVERLAY::Arc( arc.GetCenter(), radius, start_angle, start_angle + angle ); |
|||
|
|||
COLOR4D prevStrokeCol = KIGFX::VIEW_OVERLAY::GetStrokeColor(); |
|||
COLOR4D lightStrokeCol = prevStrokeCol.WithAlpha(0.5); |
|||
KIGFX::VIEW_OVERLAY::SetStrokeColor( lightStrokeCol ); |
|||
|
|||
KIGFX::VIEW_OVERLAY::SetLineWidth( arc.GetWidth() ); |
|||
KIGFX::VIEW_OVERLAY::Arc( arc.GetCenter(), radius, start_angle, start_angle + angle ); |
|||
|
|||
KIGFX::VIEW_OVERLAY::SetStrokeColor( prevStrokeCol ); |
|||
} |
|||
|
|||
void PNS_LOG_VIEWER_OVERLAY::DrawAnnotations() |
|||
{ |
|||
m_labelMgr->Redraw( this ); |
|||
} |
|||
|
|||
|
|||
PNS_LOG_VIEWER_FRAME::PNS_LOG_VIEWER_FRAME( wxFrame* frame ) : PNS_LOG_VIEWER_FRAME_BASE( frame ) |
|||
{ |
|||
LoadSettings(); |
|||
createView( this, PCB_DRAW_PANEL_GAL::GAL_TYPE_OPENGL ); |
|||
|
|||
m_viewSizer->Add( m_galPanel.get(), 1, wxEXPAND, 5 ); |
|||
|
|||
Layout(); |
|||
|
|||
Show( true ); |
|||
Maximize(); |
|||
Raise(); |
|||
|
|||
auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( |
|||
m_galPanel->GetView()->GetPainter()->GetSettings() ); |
|||
|
|||
|
|||
PCB_DISPLAY_OPTIONS opts; |
|||
|
|||
opts.m_ZoneDisplayMode = ZONE_DISPLAY_MODE::SHOW_ZONE_OUTLINE; |
|||
|
|||
double opacity = 0.5; |
|||
|
|||
opts.m_TrackOpacity = opacity; ///< Opacity override for all tracks
|
|||
opts.m_ViaOpacity = opacity; ///< Opacity override for all types of via
|
|||
opts.m_PadOpacity = opacity; ///< Opacity override for SMD pads and PTHs
|
|||
opts.m_ZoneOpacity = opacity; ///< Opacity override for filled zone areas
|
|||
|
|||
settings->LoadDisplayOptions( opts ); |
|||
|
|||
|
|||
m_listPopupMenu = new wxMenu( wxT( "" ) ); |
|||
m_listPopupMenu->Append( ID_LIST_COPY, wxT( "Copy selected geometry" ), wxT( "" ), |
|||
wxITEM_NORMAL ); |
|||
m_listPopupMenu->Append( ID_LIST_SHOW_ALL, wxT( "Show all" ), wxT( "" ), wxITEM_NORMAL ); |
|||
m_listPopupMenu->Append( ID_LIST_SHOW_NONE, wxT( "Show none" ), wxT( "" ), wxITEM_NORMAL ); |
|||
|
|||
m_itemList->Connect( m_itemList->GetId(), wxEVT_TREELIST_ITEM_CONTEXT_MENU, |
|||
wxMouseEventHandler( PNS_LOG_VIEWER_FRAME::onListRightClick ), nullptr, |
|||
this ); |
|||
//m_itemList->Connect(m_itemList->GetId(),wxEVT_LISTBOX,wxCommandEventHandler(PNS_LOG_VIEWER_FRAME::onListSelect),nullptr,this);
|
|||
m_itemList->Connect( m_itemList->GetId(), wxEVT_TREELIST_SELECTION_CHANGED, |
|||
wxCommandEventHandler( PNS_LOG_VIEWER_FRAME::onListSelect ), |
|||
nullptr, this ); |
|||
m_itemList->Connect( m_itemList->GetId(), wxEVT_TREELIST_ITEM_CHECKED, |
|||
wxCommandEventHandler( PNS_LOG_VIEWER_FRAME::onListChecked ), |
|||
nullptr, this ); |
|||
|
|||
m_itemList->AppendColumn( "Type" ); |
|||
m_itemList->AppendColumn( "Value" ); |
|||
m_itemList->AppendColumn( "File" ); |
|||
m_itemList->AppendColumn( "Method" ); |
|||
m_itemList->AppendColumn( "Line" ); |
|||
|
|||
m_overlay.reset( new PNS_LOG_VIEWER_OVERLAY ( m_galPanel->GetGAL() ) ); |
|||
m_galPanel->GetView()->Add( m_overlay.get() ); |
|||
} |
|||
|
|||
|
|||
PNS_LOG_VIEWER_FRAME::~PNS_LOG_VIEWER_FRAME() |
|||
{ |
|||
m_overlay = nullptr; |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::createUserTools() |
|||
{ |
|||
|
|||
} |
|||
|
|||
|
|||
PNS_DEBUG_STAGE* PNS_LOG_VIEWER_FRAME::getCurrentStage() |
|||
{ |
|||
PNS_TEST_DEBUG_DECORATOR* dbgd = m_logPlayer->GetDebugDecorator(); |
|||
int count = dbgd->GetStageCount(); |
|||
|
|||
int iter = m_rewindIter; |
|||
|
|||
if( count <= 0 ) |
|||
return nullptr; |
|||
|
|||
if( iter < 0 ) |
|||
iter = 0; |
|||
|
|||
if( iter >= count ) |
|||
iter = count - 1; |
|||
|
|||
return dbgd->GetStage( iter ); |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::drawLoggedItems( int iter ) |
|||
{ |
|||
if( !m_logPlayer ) |
|||
return; |
|||
|
|||
PNS_DEBUG_STAGE* st = getCurrentStage(); |
|||
|
|||
if( !st ) |
|||
return; |
|||
|
|||
m_overlay.reset( new PNS_LOG_VIEWER_OVERLAY ( m_galPanel->GetGAL() ) ); |
|||
m_galPanel->GetView()->Add( m_overlay.get() ); |
|||
//m_galPanel->GetGAL()->EnableDepthTest( false );
|
|||
|
|||
auto drawShapes = [&]( PNS_DEBUG_SHAPE* ent ) -> bool |
|||
{ |
|||
bool isEnabled = ent->IsVisible(); |
|||
bool isSelected = false; |
|||
|
|||
if( !isEnabled ) |
|||
return true; |
|||
|
|||
for( auto& sh : ent->m_shapes ) |
|||
{ |
|||
COLOR4D color = ent->m_color; |
|||
int lineWidth = ent->m_width; |
|||
|
|||
m_overlay->SetIsStroke( true ); |
|||
m_overlay->SetIsFill( false ); |
|||
|
|||
if( isSelected ) |
|||
{ |
|||
color.Brighten( 0.5 ); |
|||
} |
|||
|
|||
color.a = 1.0; |
|||
|
|||
m_overlay->SetStrokeColor( color ); |
|||
m_overlay->SetLineWidth( m_showThinLines ? 10000 : ent->m_width ); |
|||
|
|||
switch( sh->Type() ) |
|||
{ |
|||
case SH_CIRCLE: |
|||
{ |
|||
auto cir = static_cast<SHAPE_CIRCLE*>( sh ); |
|||
m_overlay->Circle( cir->GetCenter(), cir->GetRadius() ); |
|||
|
|||
break; |
|||
} |
|||
case SH_RECT: |
|||
{ |
|||
auto rect = static_cast<SHAPE_RECT*>( sh ); |
|||
m_overlay->Rectangle( rect->GetPosition(), rect->GetPosition() + rect->GetSize() ); |
|||
|
|||
break; |
|||
} |
|||
case SH_LINE_CHAIN: |
|||
{ |
|||
auto lc = static_cast<SHAPE_LINE_CHAIN*>( sh ); |
|||
m_overlay->AnnotatedPolyline( *lc, ent->m_name.ToStdString(), ent->m_hasLabels && isSelected ); |
|||
|
|||
break; |
|||
|
|||
} |
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
}; |
|||
|
|||
st->m_entries->IterateTree( drawShapes ); |
|||
|
|||
m_overlay->DrawAnnotations(); |
|||
|
|||
m_galPanel->GetView()->MarkDirty(); |
|||
m_galPanel->GetParent()->Refresh(); |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::SetLogFile( PNS_LOG_FILE* aLog ) |
|||
{ |
|||
m_logFile.reset( aLog ); |
|||
|
|||
SetBoard( m_logFile->GetBoard() ); |
|||
|
|||
m_logPlayer.reset( new PNS_LOG_PLAYER ); |
|||
|
|||
m_logPlayer->SetMode( PNS::PNS_MODE_ROUTE_SINGLE ); |
|||
m_logPlayer->ReplayLog( m_logFile.get(), 0, 0, -1); |
|||
|
|||
auto dbgd = m_logPlayer->GetDebugDecorator(); |
|||
int n_stages = dbgd->GetStageCount(); |
|||
m_rewindSlider->SetMax( n_stages - 1 ); |
|||
m_rewindSlider->SetValue( n_stages - 1 ); |
|||
m_rewindIter = n_stages - 1; |
|||
|
|||
auto extents = m_board->GetBoundingBox(); |
|||
|
|||
|
|||
BOX2D bbd; |
|||
bbd.SetOrigin( extents.GetOrigin() ); |
|||
bbd.SetWidth( extents.GetWidth() ); |
|||
bbd.SetHeight( extents.GetHeight() ); |
|||
bbd.Inflate( std::min( bbd.GetWidth(), bbd.GetHeight() ) / 5 ); |
|||
|
|||
m_galPanel->GetView()->SetViewport( bbd ); |
|||
|
|||
drawLoggedItems( m_rewindIter ); |
|||
updateDumpPanel( m_rewindIter ); |
|||
updatePnsPreviewItems( m_rewindIter ); |
|||
} |
|||
|
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::SetBoard2( std::shared_ptr<BOARD> aBoard ) |
|||
{ |
|||
SetBoard( aBoard ); |
|||
|
|||
auto extents = m_board->GetBoundingBox(); |
|||
|
|||
BOX2D bbd; |
|||
bbd.SetOrigin( extents.GetOrigin() ); |
|||
bbd.SetWidth( extents.GetWidth() ); |
|||
bbd.SetHeight( extents.GetHeight() ); |
|||
bbd.Inflate( std::min( bbd.GetWidth(), bbd.GetHeight() ) / 5 ); |
|||
|
|||
m_galPanel->GetView()->SetViewport( bbd ); |
|||
} |
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onReload( wxCommandEvent& event ) |
|||
{ |
|||
event.Skip(); |
|||
} |
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onExit( wxCommandEvent& event ) |
|||
{ |
|||
event.Skip(); |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onListChecked( wxCommandEvent& event ) |
|||
{ |
|||
syncModel(); |
|||
drawLoggedItems( m_rewindIter ); |
|||
} |
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onShowThinLinesChecked( wxCommandEvent& event ) |
|||
{ |
|||
m_showThinLines = event.GetInt(); |
|||
drawLoggedItems( m_rewindIter ); |
|||
updatePnsPreviewItems( m_rewindIter ); |
|||
} |
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onShowRPIsChecked( wxCommandEvent& event ) |
|||
{ |
|||
m_showRPIs = event.GetInt(); |
|||
drawLoggedItems( m_rewindIter ); |
|||
updatePnsPreviewItems( m_rewindIter ); |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onRewindScroll( wxScrollEvent& event ) |
|||
{ |
|||
m_rewindIter = event.GetPosition(); |
|||
drawLoggedItems( m_rewindIter ); |
|||
updateDumpPanel( m_rewindIter ); |
|||
updatePnsPreviewItems( m_rewindIter ); |
|||
char str[128]; |
|||
sprintf( str, "%d", m_rewindIter ); |
|||
m_rewindPos->SetValue( str ); |
|||
event.Skip(); |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onBtnRewindLeft( wxCommandEvent& event ) |
|||
{ |
|||
if( m_rewindIter > 0 ) |
|||
{ |
|||
m_rewindIter--; |
|||
drawLoggedItems( m_rewindIter ); |
|||
updateDumpPanel( m_rewindIter ); |
|||
updatePnsPreviewItems( m_rewindIter ); |
|||
char str[128]; |
|||
sprintf( str, "%d", m_rewindIter ); |
|||
m_rewindPos->SetValue( str ); |
|||
} |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onBtnRewindRight( wxCommandEvent& event ) |
|||
{ |
|||
auto dbgd = m_logPlayer->GetDebugDecorator(); |
|||
int count = dbgd->GetStageCount(); |
|||
|
|||
if( m_rewindIter < count ) |
|||
{ |
|||
m_rewindIter++; |
|||
drawLoggedItems( m_rewindIter ); |
|||
updateDumpPanel( m_rewindIter ); |
|||
updatePnsPreviewItems( m_rewindIter ); |
|||
char str[128]; |
|||
sprintf( str, "%d", m_rewindIter ); |
|||
m_rewindPos->SetValue( str ); |
|||
} |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onRewindCountText( wxCommandEvent& event ) |
|||
{ |
|||
if( !m_logPlayer ) |
|||
return; |
|||
|
|||
int val = wxAtoi( m_rewindPos->GetValue() ); |
|||
|
|||
auto dbgd = m_logPlayer->GetDebugDecorator(); |
|||
int count = dbgd->GetStageCount(); |
|||
|
|||
if( val < 0 ) |
|||
val = 0; |
|||
|
|||
if( val >= count ) |
|||
val = count - 1; |
|||
|
|||
m_rewindIter = val; |
|||
m_rewindSlider->SetValue( m_rewindIter ); |
|||
drawLoggedItems( m_rewindIter ); |
|||
updateDumpPanel( m_rewindIter ); |
|||
updatePnsPreviewItems( m_rewindIter ); |
|||
|
|||
event.Skip(); |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::syncModel() |
|||
{ |
|||
for( wxTreeListItem item = m_itemList->GetFirstItem(); item.IsOk(); |
|||
item = m_itemList->GetNextItem( item ) ) |
|||
{ |
|||
WX_SHAPE_TREE_ITEM_DATA* idata = |
|||
static_cast<WX_SHAPE_TREE_ITEM_DATA*>( m_itemList->GetItemData( item ) ); |
|||
|
|||
if( idata ) |
|||
{ |
|||
bool checked = m_itemList->GetCheckedState( item ) == wxCHK_CHECKED; |
|||
bool selected = m_itemList->IsSelected( item ); |
|||
idata->m_item->m_visible = checked || selected; |
|||
idata->m_item->m_selected = selected; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onListRightClick( wxMouseEvent& event ) |
|||
{ |
|||
auto sel = m_itemList->GetPopupMenuSelectionFromUser( *m_listPopupMenu ); |
|||
|
|||
switch( sel ) |
|||
{ |
|||
case ID_LIST_SHOW_NONE: |
|||
m_itemList->CheckItemRecursively( m_itemList->GetRootItem(), wxCHK_UNCHECKED ); |
|||
syncModel(); |
|||
drawLoggedItems( m_rewindIter ); |
|||
break; |
|||
case ID_LIST_SHOW_ALL: |
|||
m_itemList->CheckItemRecursively( m_itemList->GetRootItem(), wxCHK_CHECKED ); |
|||
syncModel(); |
|||
drawLoggedItems( m_rewindIter ); |
|||
break; |
|||
case ID_LIST_COPY: |
|||
{ |
|||
wxString s; |
|||
|
|||
PNS_DEBUG_STAGE* st = getCurrentStage(); |
|||
|
|||
if( !st ) |
|||
return; |
|||
|
|||
auto formatShapes = [&]( PNS_DEBUG_SHAPE* ent ) -> bool |
|||
{ |
|||
if( ent->m_selected ) |
|||
{ |
|||
for( auto sh : ent->m_shapes ) |
|||
{ |
|||
s += "// " + ent->m_name + "\n " + sh->Format() + "; \n"; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
}; |
|||
|
|||
st->m_entries->IterateTree( formatShapes ); |
|||
|
|||
if( wxTheClipboard->Open() ) |
|||
{ |
|||
// This data objects are held by the clipboard,
|
|||
// so do not delete them in the app.
|
|||
wxTheClipboard->SetData( new wxTextDataObject( s ) ); |
|||
wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
|
|||
wxTheClipboard->Close(); |
|||
} |
|||
|
|||
return; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::onListSelect( wxCommandEvent& event ) |
|||
{ |
|||
syncModel(); |
|||
drawLoggedItems( m_rewindIter ); |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::buildListTree( wxTreeListItem item, |
|||
PNS_DEBUG_SHAPE* ent, int depth ) |
|||
{ |
|||
#ifdef EXTRA_VERBOSE
|
|||
for( int i = 0; i < depth * 2; i++ ) |
|||
printf( " " ); |
|||
|
|||
if( ent->m_msg.length() ) |
|||
printf( "MSG: %s\n", ent->m_msg.c_str() ); |
|||
else |
|||
printf( "SHAPES: %s [%d]\n", ent->m_name.c_str(), ent->m_children.size() ); |
|||
#endif
|
|||
|
|||
wxTreeListItem ritem; |
|||
|
|||
printf("depth %d\n", depth ); |
|||
|
|||
if( ent->m_msg.length() ) |
|||
{ |
|||
ritem = m_itemList->AppendItem( item, "Child" ); |
|||
m_itemList->SetItemText( ritem, 0, "Message" ); |
|||
m_itemList->SetItemText( ritem, 1, ent->m_msg ); |
|||
} |
|||
else |
|||
{ |
|||
ritem = m_itemList->AppendItem( item, "Child" ); |
|||
int n_verts = 0; |
|||
for(auto sh : ent->m_shapes ) |
|||
{ |
|||
if ( sh->Type() == SH_LINE_CHAIN ) |
|||
{ |
|||
n_verts += static_cast<const SHAPE_LINE_CHAIN*>( sh )->PointCount(); |
|||
} |
|||
} |
|||
m_itemList->SetItemText( ritem, 0, wxString::Format( "Shapes [%d verts]", n_verts ) ); |
|||
m_itemList->SetItemText( ritem, 1, ent->m_name ); |
|||
} |
|||
|
|||
m_itemList->SetItemText( ritem, 2, wxFileNameFromPath( ent->m_srcLoc.fileName ) ); |
|||
m_itemList->SetItemText( ritem, 3, ent->m_srcLoc.funcName ); |
|||
m_itemList->SetItemText( ritem, 4, wxString::Format("%d", ent->m_srcLoc.line ) ); |
|||
|
|||
m_itemList->SetItemData( ritem, new WX_SHAPE_TREE_ITEM_DATA( ent ) ); |
|||
|
|||
if( !ent->m_children.size() ) |
|||
return; |
|||
|
|||
for( auto child : ent->m_children ) |
|||
{ |
|||
buildListTree( ritem, child, depth + 1 ); |
|||
} |
|||
} |
|||
|
|||
|
|||
static void expandAllChildren( wxTreeListCtrl* tree, int maxLevel = 0 ) |
|||
{ |
|||
wxTreeListItem child = tree->GetFirstItem (); |
|||
|
|||
while( child.IsOk() ) |
|||
{ |
|||
WX_SHAPE_TREE_ITEM_DATA* idata = |
|||
static_cast<WX_SHAPE_TREE_ITEM_DATA*>( tree->GetItemData( child ) ); |
|||
|
|||
if( idata->m_item->m_level <= maxLevel ) |
|||
tree->Expand ( child ); |
|||
else |
|||
tree->Collapse ( child ); |
|||
child = tree->GetNextItem( child ); |
|||
} |
|||
} |
|||
|
|||
static void collapseAllChildren( wxTreeListCtrl* tree ) |
|||
{ |
|||
wxTreeListItem child = tree->GetFirstItem (); |
|||
|
|||
while( child.IsOk() ) |
|||
{ |
|||
tree->Collapse ( child ); |
|||
child = tree->GetNextItem( child ); |
|||
} |
|||
} |
|||
|
|||
|
|||
void PNS_LOG_VIEWER_FRAME::updateDumpPanel( int iter ) |
|||
{ |
|||
if( !m_logPlayer ) |
|||
return; |
|||
|
|||
auto dbgd = m_logPlayer->GetDebugDecorator(); |
|||
int count = dbgd->GetStageCount(); |
|||
|
|||
wxArrayString dumpStrings; |
|||
|
|||
if( count <= 0 ) |
|||
return; |
|||
|
|||
if( iter < 0 ) |
|||
iter = 0; |
|||
|
|||
if( iter >= count ) |
|||
iter = count - 1; |
|||
|
|||
auto st = dbgd->GetStage( iter ); |
|||
auto rootItem = m_itemList->GetRootItem(); |
|||
|
|||
m_itemList->DeleteAllItems(); |
|||
buildListTree( rootItem, st->m_entries ); |
|||
m_itemList->CheckItemRecursively( rootItem, wxCHK_UNCHECKED ); |
|||
|
|||
expandAllChildren( m_itemList ); |
|||
|
|||
m_itemList->Refresh(); |
|||
} |
|||
|
|||
void PNS_LOG_VIEWER_FRAME::updatePnsPreviewItems( int iter ) |
|||
{ |
|||
auto viewTracker = m_logPlayer->GetViewTracker(); |
|||
PNS_LOG_VIEW_TRACKER::VIEW_ENTRIES& entries = viewTracker->GetEntriesForStage( iter ); |
|||
auto view = m_galPanel->GetView(); |
|||
printf("DBG updatePnsPreviewItems: %d items\n", entries.size() ); |
|||
|
|||
m_previewItems.reset( new KIGFX::VIEW_GROUP( m_galPanel->GetView() ) ); |
|||
m_galPanel->GetView()->Add( m_previewItems.get() ); |
|||
m_previewItems->SetLayer( LAYER_SELECT_OVERLAY ) ; |
|||
m_galPanel->GetView()->SetLayerVisible( LAYER_SELECT_OVERLAY ); |
|||
|
|||
if( !m_showRPIs ) |
|||
return; |
|||
|
|||
for( auto& ent : entries ) |
|||
{ |
|||
if ( ent.isHideOp ) |
|||
{ |
|||
|
|||
auto parent = ent.item->Parent(); |
|||
if( parent ) |
|||
{ |
|||
|
|||
view->Hide( parent ); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( ent.item, view ); |
|||
pitem->Update( ent.item ); |
|||
m_previewItems->Add(pitem); |
|||
// printf("DBG vadd %p total %d\n", pitem, m_previewItems->GetSize() );
|
|||
} |
|||
} |
|||
|
|||
view->SetVisible( m_previewItems.get(), true ); |
|||
|
|||
view->Update( m_previewItems.get() ); |
|||
printf("DBG vgrp %p total %d\n", m_previewItems.get(), m_previewItems->GetSize() ); |
|||
|
|||
|
|||
//view->UpdateAllItems( KIGFX::ALL );
|
|||
} |
|||
|
|||
#if 0
|
|||
|
|||
static BOARD* loadBoard( const std::string& filename ) |
|||
{ |
|||
PLUGIN::RELEASER pi( new PCB_PLUGIN ); |
|||
BOARD* brd = nullptr; |
|||
|
|||
try |
|||
{ |
|||
brd = pi->Load( wxString( filename.c_str() ), nullptr, nullptr ); |
|||
} |
|||
catch( const IO_ERROR& ) |
|||
{ |
|||
return nullptr; |
|||
} |
|||
|
|||
return brd; |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
int render_perftest_main_func( int argc, char* argv[] ) |
|||
{ |
|||
auto frame = new PNS_LOG_VIEWER_FRAME( nullptr ); |
|||
|
|||
// drcCreateTestsProviderClearance();
|
|||
// drcCreateTestsProviderEdgeClearance();
|
|||
|
|||
if( argc >= 2 && std::string( argv[1] ) == "-h" ) |
|||
{ |
|||
printf( "PCB render performance test. Just renders a board without UI update overhead.\n" ); |
|||
return 0; |
|||
} |
|||
|
|||
if( argc < 2 ) |
|||
{ |
|||
printf( "Expected parameters: board_file\n" ); |
|||
return 0; |
|||
} |
|||
|
|||
PROF_TIMER cnt("load-board"); |
|||
std::shared_ptr<BOARD> brd ( loadBoard( argv[1] ) ); |
|||
cnt.Stop(); |
|||
|
|||
KI_TRACE( traceGalProfile, "%s\n", cnt.to_string() ); |
|||
|
|||
frame->SetBoard2( brd ); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
static bool registered3 = UTILITY_REGISTRY::Register( { |
|||
"render_perftest", |
|||
"Renderer performance test", |
|||
render_perftest_main_func, |
|||
} ); |
|||
|
|||
|
|||
VECTOR2I NearestPointFixpt( SEG seg, const VECTOR2I& aP ) |
|||
{ |
|||
VECTOR2I d = seg.B - seg.A; |
|||
SEG::ecoord l_squared = d.Dot( d ); |
|||
|
|||
if( l_squared == 0 ) |
|||
return seg.A; |
|||
|
|||
SEG::ecoord t = d.Dot( aP - seg.A ); |
|||
|
|||
if( t < 0 ) |
|||
return seg.A; |
|||
else if( t > l_squared ) |
|||
return seg.B; |
|||
|
|||
int xp = rescale( t, (SEG::ecoord) d.x, l_squared ); |
|||
int yp = rescale( t, (SEG::ecoord) d.y, l_squared ); |
|||
|
|||
return seg.A + VECTOR2I( xp, yp ); |
|||
} |
|||
|
|||
|
|||
VECTOR2D NearestPointDbl( SEG seg, const VECTOR2I& aP ) |
|||
{ |
|||
VECTOR2D d = seg.B - seg.A; |
|||
double l_squared = d.Dot(d); |
|||
|
|||
if( l_squared == 0 ) |
|||
return seg.A; |
|||
|
|||
double t = d.Dot(VECTOR2D( aP - seg.A ) ); |
|||
|
|||
if( t < 0 ) |
|||
return seg.A; |
|||
else if( t > l_squared ) |
|||
return seg.B; |
|||
|
|||
double xp = t * d.x / l_squared; |
|||
double yp = t * d.y / l_squared; |
|||
|
|||
return VECTOR2D(seg.A) + VECTOR2D( xp, yp ); |
|||
} |
|||
|
|||
int ttt_main_func( int argc, char* argv[] ) |
|||
{ |
|||
int n = 1000000; |
|||
std::vector<VECTOR2I> pts; |
|||
std::vector<SEG> segs; |
|||
std::vector<VECTOR2D> rv; |
|||
std::vector<VECTOR2I> rvi; |
|||
|
|||
|
|||
rv.resize(n); |
|||
rvi.resize(n); |
|||
|
|||
for (int i = 0; i < n ;i++) |
|||
{ |
|||
pts.push_back(VECTOR2I(random()%100000000, random()%100000000)); |
|||
segs.push_back(SEG( VECTOR2I(random()%100000000, random()%100000000), VECTOR2I(random()%100000000, random()%100000000) ) ); |
|||
} |
|||
|
|||
PROF_TIMER tmrFix("nearest-fixpt"); |
|||
for(int i = 0; i < n ; i++) |
|||
{ |
|||
rvi[i] = NearestPointFixpt( segs[i], pts[i]); |
|||
} |
|||
tmrFix.Show(); |
|||
|
|||
PROF_TIMER tmrDbl("nearest-double"); |
|||
for(int i = 0; i < n ; i++) |
|||
{ |
|||
rv[i] = NearestPointDbl( segs[i], pts[i]); |
|||
} |
|||
tmrDbl.Show(); |
|||
return 0; |
|||
} |
|||
|
|||
|
|||
|
|||
static bool registered4 = UTILITY_REGISTRY::Register( { |
|||
"ttt", |
|||
"Renderer performance test", |
|||
ttt_main_func, |
|||
} ); |
|||
|
|||
#endif
|
@ -0,0 +1,278 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020-2021 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 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 "pns_test_debug_decorator.h"
|
|||
|
|||
#include <router/pns_item.h>
|
|||
|
|||
PNS_DEBUG_SHAPE::PNS_DEBUG_SHAPE( PNS_DEBUG_SHAPE* aParent ) |
|||
{ |
|||
m_iter = 0; |
|||
m_color = KIGFX::COLOR4D::WHITE; |
|||
m_width = 10000; |
|||
m_name = "<unknown>"; |
|||
m_parent = aParent; |
|||
m_visible = true; |
|||
m_selected = false; |
|||
m_level = 0; |
|||
} |
|||
|
|||
PNS_DEBUG_SHAPE::~PNS_DEBUG_SHAPE() |
|||
{ |
|||
for( auto s : m_shapes ) |
|||
{ |
|||
delete s; |
|||
} |
|||
|
|||
for( auto ch : m_children ) |
|||
{ |
|||
delete ch; |
|||
} |
|||
} |
|||
|
|||
PNS_DEBUG_SHAPE* PNS_DEBUG_SHAPE::NewChild() |
|||
{ |
|||
PNS_DEBUG_SHAPE* ent = new PNS_DEBUG_SHAPE( this ); |
|||
m_children.push_back( ent ); |
|||
|
|||
return ent; |
|||
} |
|||
|
|||
void PNS_DEBUG_SHAPE::AddChild( PNS_DEBUG_SHAPE* ent ) |
|||
{ |
|||
ent->m_parent = this; |
|||
m_children.push_back( ent ); |
|||
} |
|||
|
|||
bool PNS_DEBUG_SHAPE::IsVisible() const |
|||
{ |
|||
if( m_visible ) |
|||
return true; |
|||
|
|||
auto parent = m_parent; |
|||
|
|||
while( parent ) |
|||
{ |
|||
if( parent->m_visible ) |
|||
return true; |
|||
|
|||
parent = parent->m_parent; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
void PNS_DEBUG_SHAPE::IterateTree( |
|||
std::function<bool( PNS_DEBUG_SHAPE* )> visitor, int depth ) |
|||
{ |
|||
if( !visitor( this ) ) |
|||
return; |
|||
|
|||
|
|||
for( auto child : m_children ) |
|||
{ |
|||
child->IterateTree( visitor, depth + 1 ); |
|||
} |
|||
} |
|||
|
|||
PNS_DEBUG_STAGE::PNS_DEBUG_STAGE() |
|||
{ |
|||
m_name = "<unknown>"; |
|||
m_iter = 0; |
|||
m_entries = new PNS_DEBUG_SHAPE(); |
|||
} |
|||
|
|||
PNS_DEBUG_STAGE::~PNS_DEBUG_STAGE() |
|||
{ |
|||
} |
|||
|
|||
|
|||
PNS_TEST_DEBUG_DECORATOR::PNS_TEST_DEBUG_DECORATOR() |
|||
{ |
|||
m_iter = 0; |
|||
m_grouping = false; |
|||
m_activeEntry = nullptr; |
|||
SetDebugEnabled( true ); |
|||
} |
|||
|
|||
PNS_TEST_DEBUG_DECORATOR::~PNS_TEST_DEBUG_DECORATOR() |
|||
{ |
|||
// fixme: I know it's a hacky tool but it should clean after itself at some point...
|
|||
|
|||
} |
|||
|
|||
|
|||
|
|||
PNS_DEBUG_STAGE* PNS_TEST_DEBUG_DECORATOR::currentStage() |
|||
{ |
|||
if( m_stages.empty() ) |
|||
m_stages.push_back( new PNS_DEBUG_STAGE() ); |
|||
|
|||
return m_stages.back(); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::BeginGroup( const wxString& name, int aLevel, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
PNS_DEBUG_STAGE* stage = currentStage(); |
|||
PNS_DEBUG_SHAPE* ent = new PNS_DEBUG_SHAPE(); |
|||
|
|||
ent->m_name = name; |
|||
ent->m_iter = m_iter; |
|||
ent->m_level = aLevel; |
|||
|
|||
if( m_activeEntry ) |
|||
{ |
|||
m_activeEntry->AddChild( ent ); |
|||
} |
|||
|
|||
m_activeEntry = ent; |
|||
m_grouping = true; |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::EndGroup( const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
if( !m_activeEntry ) |
|||
return; |
|||
|
|||
m_activeEntry = m_activeEntry->m_parent; |
|||
|
|||
if( !m_activeEntry ) |
|||
m_grouping = false; |
|||
} |
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::addEntry( PNS_DEBUG_SHAPE* ent ) |
|||
{ |
|||
auto st = currentStage(); |
|||
m_activeEntry->AddChild( ent ); |
|||
} |
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::AddPoint( const VECTOR2I& aP, const KIGFX::COLOR4D& aColor, |
|||
int aSize, const wxString& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
auto sh = new SHAPE_LINE_CHAIN; |
|||
|
|||
sh->Append( aP.x - aSize, aP.y - aSize ); |
|||
sh->Append( aP.x + aSize, aP.y + aSize ); |
|||
sh->Append( aP.x, aP.y ); |
|||
sh->Append( aP.x - aSize, aP.y + aSize ); |
|||
sh->Append( aP.x + aSize, aP.y - aSize ); |
|||
|
|||
PNS_DEBUG_SHAPE* ent = new PNS_DEBUG_SHAPE(); |
|||
|
|||
ent->m_shapes.push_back( sh ); |
|||
ent->m_color = aColor; |
|||
ent->m_width = 30000; |
|||
ent->m_iter = m_iter; |
|||
ent->m_name = aName; |
|||
ent->m_hasLabels = false; |
|||
ent->m_srcLoc = aSrcLoc; |
|||
|
|||
addEntry( ent ); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::AddItem( const PNS::ITEM* aItem, const KIGFX::COLOR4D& aColor, |
|||
int aOverrideWidth, const wxString& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
auto sh = aItem->Shape()->Clone(); |
|||
PNS_DEBUG_SHAPE* ent = new PNS_DEBUG_SHAPE(); |
|||
|
|||
ent->m_shapes.push_back( sh ); |
|||
ent->m_color = aColor; |
|||
ent->m_width = aOverrideWidth; |
|||
ent->m_name = aName; |
|||
ent->m_iter = m_iter; |
|||
ent->m_srcLoc = aSrcLoc; |
|||
|
|||
addEntry( ent ); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::AddShape( const SHAPE* aShape, const KIGFX::COLOR4D& aColor, |
|||
int aOverrideWidth, const wxString& aName, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
auto sh = aShape->Clone(); |
|||
PNS_DEBUG_SHAPE* ent = new PNS_DEBUG_SHAPE(); |
|||
|
|||
ent->m_shapes.push_back( sh ); |
|||
ent->m_color = aColor; |
|||
ent->m_width = aOverrideWidth; |
|||
ent->m_name = aName; |
|||
ent->m_iter = m_iter; |
|||
ent->m_srcLoc = aSrcLoc; |
|||
|
|||
addEntry( ent ); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::Message( const wxString& msg, const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
PNS_DEBUG_SHAPE* ent = new PNS_DEBUG_SHAPE(); |
|||
ent->m_msg = msg.c_str(); |
|||
ent->m_srcLoc = aSrcLoc; |
|||
addEntry( ent ); |
|||
} |
|||
|
|||
|
|||
void PNS_TEST_DEBUG_DECORATOR::NewStage( const wxString& name, int iter, |
|||
const SRC_LOCATION_INFO& aSrcLoc ) |
|||
{ |
|||
PNS_DEBUG_STAGE* stage = new PNS_DEBUG_STAGE(); |
|||
stage->m_name = name; |
|||
stage->m_iter = iter; |
|||
|
|||
m_stages.push_back( new PNS_DEBUG_STAGE ); |
|||
m_activeEntry = m_stages.back()->m_entries; |
|||
} |
|||
|
|||
|
|||
|
|||
BOX2I PNS_TEST_DEBUG_DECORATOR::GetStageExtents( int stage ) const |
|||
{ |
|||
PNS_DEBUG_STAGE* st = m_stages[stage]; |
|||
BOX2I bb; |
|||
bool first = true; |
|||
|
|||
auto visitor = [&]( PNS_DEBUG_SHAPE* ent ) -> bool { |
|||
for( auto sh : ent->m_shapes ) |
|||
{ |
|||
if( first ) |
|||
bb = sh->BBox(); |
|||
else |
|||
bb.Merge( sh->BBox() ); |
|||
|
|||
first = false; |
|||
} |
|||
|
|||
return true; |
|||
}; |
|||
|
|||
return bb; |
|||
} |
@ -0,0 +1,114 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020-2021 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 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 __PNS_TEST_DEBUG_DECORATOR_H |
|||
#define __PNS_TEST_DEBUG_DECORATOR_H |
|||
|
|||
#include <geometry/shape.h> |
|||
|
|||
#include <router/pns_debug_decorator.h> |
|||
|
|||
class PNS_DEBUG_SHAPE |
|||
{ |
|||
public: |
|||
PNS_DEBUG_SHAPE( PNS_DEBUG_SHAPE* aParent = nullptr ); |
|||
~PNS_DEBUG_SHAPE(); |
|||
|
|||
PNS_DEBUG_SHAPE* NewChild(); |
|||
void AddChild( PNS_DEBUG_SHAPE* ent ); |
|||
bool IsVisible() const; |
|||
void IterateTree( std::function<bool( PNS_DEBUG_SHAPE* )> visitor, int depth = 0 ); |
|||
|
|||
PNS_DEBUG_SHAPE* m_parent; |
|||
std::vector<SHAPE*> m_shapes; |
|||
std::vector<PNS_DEBUG_SHAPE*> m_children; |
|||
KIGFX::COLOR4D m_color; |
|||
int m_width; |
|||
bool m_hasLabels = true; |
|||
int m_iter; |
|||
wxString m_name; |
|||
wxString m_msg; |
|||
PNS::DEBUG_DECORATOR::SRC_LOCATION_INFO m_srcLoc; |
|||
bool m_visible; |
|||
bool m_selected; |
|||
int m_level; |
|||
}; |
|||
|
|||
struct PNS_DEBUG_STAGE |
|||
{ |
|||
PNS_DEBUG_STAGE(); |
|||
~PNS_DEBUG_STAGE(); |
|||
|
|||
wxString m_name; |
|||
int m_iter; |
|||
PNS_DEBUG_SHAPE* m_entries; |
|||
}; |
|||
|
|||
|
|||
class PNS_TEST_DEBUG_DECORATOR : public PNS::DEBUG_DECORATOR |
|||
{ |
|||
public: |
|||
PNS_TEST_DEBUG_DECORATOR(); |
|||
virtual ~PNS_TEST_DEBUG_DECORATOR(); |
|||
|
|||
virtual void SetIteration( int iter ) override { m_iter = iter; } |
|||
|
|||
virtual void Message( const wxString& msg, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void NewStage( const wxString& name, int iter, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void BeginGroup( const wxString& name, int aLevel = 0, |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
virtual void EndGroup( const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
|
|||
virtual void AddPoint( const VECTOR2I& aP, const KIGFX::COLOR4D& aColor, int aSize, |
|||
const wxString& aName = wxT( "" ), |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
|
|||
virtual void AddItem( const PNS::ITEM* aItem, const KIGFX::COLOR4D& aColor, |
|||
int aOverrideWidth = 0, const wxString& aName = wxT( "" ), |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
|
|||
virtual void AddShape( const SHAPE* aShape, const KIGFX::COLOR4D& aColor, |
|||
int aOverrideWidth = 0, const wxString& aName = wxT( "" ), |
|||
const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override; |
|||
|
|||
virtual void Clear() override{}; |
|||
|
|||
int GetStageCount() const { return m_stages.size(); } |
|||
|
|||
PNS_DEBUG_STAGE* GetStage( int index ) { return m_stages[index]; } |
|||
|
|||
BOX2I GetStageExtents( int stage ) const; |
|||
|
|||
private: |
|||
void addEntry( PNS_DEBUG_SHAPE* ent ); |
|||
PNS_DEBUG_STAGE* currentStage(); |
|||
|
|||
bool m_grouping; |
|||
PNS_DEBUG_SHAPE* m_activeEntry; |
|||
int m_iter; |
|||
std::vector<PNS_DEBUG_STAGE*> m_stages; |
|||
}; |
|||
|
|||
#endif |
Write
Preview
Loading…
Cancel
Save
Reference in new issue