/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 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 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 #include #include #include #include #include "pns_log.h" #include "router/pns_diff_pair.h" #include "router/pns_utils.h" #include "pns_log_viewer_frame.h" #include "qa/drc_proto/drc_proto.h" #define TOM_EXTRA_DEBUG class LABEL_MANAGER { public: struct LABEL { COLOR4D m_color; std::string m_msg; VECTOR2I m_target; BOX2I m_bbox; }; LABEL_MANAGER( KIGFX::GAL* aGal ) : m_gal( aGal ) {}; void Add( VECTOR2I target, std::string 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) ); VECTOR2I textDims = m_gal->GetTextLineSize( msg ); lbl.m_bbox.SetOrigin( lbl.m_target - textDims - VECTOR2I( m_textSize, m_textSize ) ); lbl.m_bbox.SetSize( textDims ); m_labels.push_back( lbl ); } void 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 Redraw( std::shared_ptr aOvl ) { recalculate(); for ( auto & lbl : m_labels ) { //printf("Draw lbl %d %d '%s'\n", lbl.m_bbox.GetOrigin().x, lbl.m_bbox.GetOrigin().y, lbl.m_msg.c_str() ); 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(), 0.0 ); VECTOR2I nearest = nearestBoxCorner( lbl.m_bbox, lbl.m_target ); aOvl->Line( lbl.m_target, nearest ); } } private: VECTOR2I 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 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 recalculate() { int iterLimit = 5; while ( iterLimit > 0 ) { printf("Iter %d\n", iterLimit ); 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 ) { // printf("%d %d mtv %d %d\n", i, j, mtv.x, mtv.y ); m_labels[i].m_bbox.Move( -mtv ); collisionsFound = true; } } } if( ! collisionsFound ) break; iterLimit--; } } KIGFX::GAL* m_gal; int m_textSize = 100000; std::vector