/*
* 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
Differential pair gap/coupling test.
Errors generated:
- DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE
- DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
- DRCE_TOO_MANY_VIAS
Todo:
- arc support.
- improve recognition of coupled segments (now anything that's parallel is considered
coupled, causing DRC errors on meanders)
*/
namespace test {
class DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING () :
m_board( nullptr )
{
}
virtual ~DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "diff_pair_coupling";
};
virtual const wxString GetDescription() const override
{
return "Tests differential pair coupling";
}
virtual int GetNumPhases() const override
{
return 1;
}
virtual std::set GetConstraintTypes() const override;
private:
BOARD* m_board;
};
};
static bool commonParallelProjection( SEG p, SEG n, SEG &pClip, SEG& nClip )
{
SEG n_proj_p( p.LineProject( n.A ), p.LineProject( n.B ) );
int64_t t_a = 0;
int64_t t_b = p.TCoef( p.B );
int64_t tproj_a = p.TCoef( n_proj_p.A );
int64_t tproj_b = p.TCoef( n_proj_p.B );
if( t_b < t_a )
std::swap( t_b, t_a );
if( tproj_b < tproj_a )
std::swap( tproj_b, tproj_a );
if( t_b <= tproj_a )
return false;
if( t_a >= tproj_b )
return false;
int64_t t[4] = { 0, p.TCoef( p.B ), p.TCoef( n_proj_p.A ), p.TCoef( n_proj_p.B ) };
std::vector tv( t, t + 4 );
std::sort( tv.begin(), tv.end() ); // fixme: awful and disgusting way of finding 2 midpoints
int64_t pLenSq = p.SquaredLength();
VECTOR2I dp = p.B - p.A;
pClip.A.x = p.A.x + rescale( (int64_t)dp.x, tv[1], pLenSq );
pClip.A.y = p.A.y + rescale( (int64_t)dp.y, tv[1], pLenSq );
pClip.B.x = p.A.x + rescale( (int64_t)dp.x, tv[2], pLenSq );
pClip.B.y = p.A.y + rescale( (int64_t)dp.y, tv[2], pLenSq );
nClip.A = n.LineProject( pClip.A );
nClip.B = n.LineProject( pClip.B );
return true;
}
struct DIFF_PAIR_KEY
{
bool operator<( const DIFF_PAIR_KEY& b ) const
{
if( netP < b.netP )
{
return true;
}
else if( netP > b.netP )
{
return false;
}
else // netP == b.netP
{
if( netN < b.netN )
return true;
else if( netN > b.netN )
return false;
else
return parentRule < b.parentRule;
}
}
int netP, netN;
DRC_RULE* parentRule;
};
struct DIFF_PAIR_COUPLED_SEGMENTS
{
SEG coupledN;
SEG coupledP;
TRACK* parentN;
TRACK* parentP;
int computedGap;
PCB_LAYER_ID layer;
bool couplingOK;
DIFF_PAIR_COUPLED_SEGMENTS() :
parentN( nullptr ),
parentP( nullptr ),
computedGap( 0 ),
layer( UNDEFINED_LAYER ),
couplingOK( false )
{}
};
struct DIFF_PAIR_ITEMS
{
std::set itemsP, itemsN;
std::vector coupled;
int totalCoupled;
int totalLengthN;
int totalLengthP;
};
static void extractDiffPairCoupledItems( DIFF_PAIR_ITEMS& aDp, DRC_RTREE& aTree )
{
for( BOARD_CONNECTED_ITEM* itemP : aDp.itemsP )
{
TRACK* sp = dyn_cast