mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-04-21 00:21:25 +00:00
DRC : Show paths for clearance and creepage
This commit is contained in:
parent
ab1b22d435
commit
07a0c980f3
common
include
pcbnew
@ -183,6 +183,8 @@ wxString LayerName( int aLayer )
|
||||
case LAYER_RATSNEST: return _( "Ratsnest" );
|
||||
case LAYER_DRC_WARNING: return _( "DRC warnings" );
|
||||
case LAYER_DRC_ERROR: return _( "DRC errors" );
|
||||
case LAYER_DRC_SHAPE1: return _( "DRC shape 1" );
|
||||
case LAYER_DRC_SHAPE2: return _( "DRC shape 2" );
|
||||
case LAYER_DRC_EXCLUSION: return _( "DRC exclusions" );
|
||||
case LAYER_MARKER_SHADOWS: return _( "DRC marker shadows" );
|
||||
case LAYER_ANCHOR: return _( "Anchors" );
|
||||
|
@ -842,44 +842,17 @@ std::vector<GAL_LAYER_ID> GAL_SET::Seq() const
|
||||
GAL_SET GAL_SET::DefaultVisible()
|
||||
{
|
||||
static const GAL_LAYER_ID visible[] = {
|
||||
LAYER_VIAS,
|
||||
LAYER_VIA_MICROVIA,
|
||||
LAYER_VIA_BBLIND,
|
||||
LAYER_VIA_THROUGH,
|
||||
// LAYER_HIDDEN_TEXT, // DEPCREATED SINCE 9.0. Invisible text hidden by default
|
||||
LAYER_ANCHOR,
|
||||
LAYER_PADS_SMD_FR,
|
||||
LAYER_PADS_SMD_BK,
|
||||
LAYER_RATSNEST,
|
||||
LAYER_GRID,
|
||||
LAYER_GRID_AXES,
|
||||
LAYER_FOOTPRINTS_FR,
|
||||
LAYER_FOOTPRINTS_BK,
|
||||
LAYER_FP_TEXT,
|
||||
LAYER_FP_VALUES,
|
||||
LAYER_FP_REFERENCES,
|
||||
LAYER_TRACKS,
|
||||
LAYER_PADS_TH,
|
||||
LAYER_PAD_PLATEDHOLES,
|
||||
LAYER_NON_PLATEDHOLES,
|
||||
LAYER_PAD_HOLEWALLS,
|
||||
LAYER_VIA_HOLES,
|
||||
LAYER_VIA_HOLEWALLS,
|
||||
LAYER_DRC_ERROR,
|
||||
LAYER_DRC_WARNING,
|
||||
// LAYER_DRC_EXCLUSION, // DRC exclusions hidden by default
|
||||
LAYER_DRAWINGSHEET,
|
||||
LAYER_GP_OVERLAY,
|
||||
LAYER_SELECT_OVERLAY,
|
||||
LAYER_PCB_BACKGROUND,
|
||||
LAYER_CURSOR,
|
||||
LAYER_AUX_ITEMS,
|
||||
LAYER_DRAW_BITMAPS,
|
||||
LAYER_PADS,
|
||||
LAYER_ZONES,
|
||||
LAYER_SHAPES,
|
||||
LAYER_LOCKED_ITEM_SHADOW,
|
||||
LAYER_CONFLICTS_SHADOW
|
||||
LAYER_VIAS, LAYER_VIA_MICROVIA, LAYER_VIA_BBLIND, LAYER_VIA_THROUGH,
|
||||
// LAYER_HIDDEN_TEXT, // DEPCREATED SINCE 9.0. Invisible text hidden by default
|
||||
LAYER_ANCHOR, LAYER_PADS_SMD_FR, LAYER_PADS_SMD_BK, LAYER_RATSNEST, LAYER_GRID,
|
||||
LAYER_GRID_AXES, LAYER_FOOTPRINTS_FR, LAYER_FOOTPRINTS_BK, LAYER_FP_TEXT, LAYER_FP_VALUES,
|
||||
LAYER_FP_REFERENCES, LAYER_TRACKS, LAYER_PADS_TH, LAYER_PAD_PLATEDHOLES,
|
||||
LAYER_NON_PLATEDHOLES, LAYER_PAD_HOLEWALLS, LAYER_VIA_HOLES, LAYER_VIA_HOLEWALLS,
|
||||
LAYER_DRC_ERROR, LAYER_DRC_WARNING, LAYER_DRC_SHAPE1, LAYER_DRC_SHAPE2,
|
||||
// LAYER_DRC_EXCLUSION, // DRC exclusions hidden by default
|
||||
LAYER_DRAWINGSHEET, LAYER_GP_OVERLAY, LAYER_SELECT_OVERLAY, LAYER_PCB_BACKGROUND,
|
||||
LAYER_CURSOR, LAYER_AUX_ITEMS, LAYER_DRAW_BITMAPS, LAYER_PADS, LAYER_ZONES, LAYER_SHAPES,
|
||||
LAYER_LOCKED_ITEM_SHADOW, LAYER_CONFLICTS_SHADOW
|
||||
};
|
||||
|
||||
static const GAL_SET saved( visible, arrayDim( visible ) );
|
||||
|
@ -235,13 +235,15 @@ enum GAL_LAYER_ID: int
|
||||
LAYER_PAD_HOLEWALLS = GAL_LAYER_ID_START + 34,
|
||||
LAYER_VIA_HOLEWALLS = GAL_LAYER_ID_START + 35,
|
||||
LAYER_DRC_WARNING = GAL_LAYER_ID_START + 36, ///< layer for drc markers with SEVERITY_WARNING
|
||||
LAYER_DRC_EXCLUSION = GAL_LAYER_ID_START + 37, ///< layer for drc markers which have been individually excluded
|
||||
LAYER_MARKER_SHADOWS = GAL_LAYER_ID_START + 38, ///< shadows for drc markers
|
||||
LAYER_DRC_SHAPE1 = GAL_LAYER_ID_START + 37, ///< Custom shape for DRC marker
|
||||
LAYER_DRC_SHAPE2 = GAL_LAYER_ID_START + 38, ///< Custom shape for DRC marker
|
||||
LAYER_DRC_EXCLUSION = GAL_LAYER_ID_START + 39, ///< layer for drc markers which have been individually excluded
|
||||
LAYER_MARKER_SHADOWS = GAL_LAYER_ID_START + 40, ///< shadows for drc markers
|
||||
|
||||
LAYER_LOCKED_ITEM_SHADOW = GAL_LAYER_ID_START + 39, ///< shadow layer for locked items
|
||||
LAYER_LOCKED_ITEM_SHADOW = GAL_LAYER_ID_START + 41, ///< shadow layer for locked items
|
||||
|
||||
LAYER_CONFLICTS_SHADOW = GAL_LAYER_ID_START + 40, ///< shadow layer for items flagged conficting
|
||||
LAYER_SHAPES = GAL_LAYER_ID_START + 41, ///< Copper graphic shape opacity/visibility (color ignored)
|
||||
LAYER_CONFLICTS_SHADOW = GAL_LAYER_ID_START + 42, ///< shadow layer for items flagged conficting
|
||||
LAYER_SHAPES = GAL_LAYER_ID_START + 43, ///< Copper graphic shape opacity/visibility (color ignored)
|
||||
|
||||
// Add layers below this point that do not have visibility controls, so don't need explicit
|
||||
// enum values
|
||||
|
@ -252,10 +252,12 @@ set( PCBNEW_GENERATORS_SRCS
|
||||
|
||||
set( PCBNEW_DRC_SRCS
|
||||
drc/drc_interactive_courtyard_clearance.cpp
|
||||
drc/drc_creepage_utils.cpp
|
||||
drc/drc_report.cpp
|
||||
drc/drc_test_provider.cpp
|
||||
drc/drc_test_provider_annular_width.cpp
|
||||
drc/drc_test_provider_disallow.cpp
|
||||
drc/drc_test_provider_clearance_base.cpp
|
||||
drc/drc_test_provider_creepage.cpp
|
||||
drc/drc_test_provider_connectivity.cpp
|
||||
drc/drc_test_provider_connection_width.cpp
|
||||
|
2475
pcbnew/drc/drc_creepage_utils.cpp
Normal file
2475
pcbnew/drc/drc_creepage_utils.cpp
Normal file
File diff suppressed because it is too large
Load Diff
728
pcbnew/drc/drc_creepage_utils.h
Normal file
728
pcbnew/drc/drc_creepage_utils.h
Normal file
@ -0,0 +1,728 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 KiCad Developers.
|
||||
* Copyright (C) 2024 Fabien Corona f.corona<at>laposte.net
|
||||
*
|
||||
* 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 _DRC_CREEPAGE_UTILS_H
|
||||
#define _DRC_CREEPAGE_UTILS_H
|
||||
|
||||
#include <common.h>
|
||||
#include <macros.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <footprint.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_track.h>
|
||||
#include <pcb_shape.h>
|
||||
#include <zone.h>
|
||||
#include <advanced_config.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_rule.h>
|
||||
#include <board.h>
|
||||
|
||||
|
||||
#include <geometry/shape_circle.h>
|
||||
|
||||
|
||||
extern bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
|
||||
const std::vector<BOARD_ITEM*>& aBe,
|
||||
const std::vector<const BOARD_ITEM*>& aDontTestAgainst );
|
||||
bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center,
|
||||
double radius, double startAngle, double endAngle );
|
||||
|
||||
struct path_connection
|
||||
{
|
||||
VECTOR2D a1;
|
||||
VECTOR2D a2;
|
||||
double weight = -1;
|
||||
bool m_show = true;
|
||||
|
||||
bool m_forceA1concavityCheck = false;
|
||||
bool m_forceA2concavityCheck = false;
|
||||
|
||||
|
||||
/** @brief Test if a path is valid
|
||||
*
|
||||
* Check if a paths intersects the board edge or a track
|
||||
*/
|
||||
bool isValid( const BOARD& aBoard, PCB_LAYER_ID aLayer,
|
||||
const std::vector<BOARD_ITEM*>& aBoardEdges,
|
||||
const std::vector<const BOARD_ITEM*>& aIgnoreForTest, SHAPE_POLY_SET* aOutline,
|
||||
const std::pair<bool, bool>& aTestLocalConcavity )
|
||||
{
|
||||
if( !aOutline )
|
||||
return true; // We keep the segment if there is a problem
|
||||
|
||||
if( !SegmentIntersectsBoard( a1, a2, aBoardEdges, aIgnoreForTest ) )
|
||||
return false;
|
||||
|
||||
// The mid point should be inside the board.
|
||||
// Tolerance of 100nm.
|
||||
|
||||
VECTOR2I midPoint = ( a1 + a2 ) / 2;
|
||||
int tolerance = 100;
|
||||
|
||||
if( !( aOutline->Contains( midPoint, -1, tolerance )
|
||||
|| aOutline->PointOnEdge( midPoint, tolerance ) ) )
|
||||
return false;
|
||||
|
||||
if( false && ( aTestLocalConcavity.first || aTestLocalConcavity.second ) )
|
||||
{
|
||||
// Test for local concavity. If it is localy convex, then it will not be a path of interest.
|
||||
|
||||
double extendLine = 1000; // extend line by 1000nm
|
||||
// In some cases, the projected point could be on the board edge
|
||||
// In such cases, we wan to keep the line.
|
||||
// We inflate the polygon to get a small margin for computation/rounding error.
|
||||
// We might keep some unnecessary lines, but it's better than loosing the important ones.
|
||||
double extendPoly = 100; // extend polygon by 10 nm
|
||||
|
||||
VECTOR2D a( double( a1.x ), double( a1.y ) );
|
||||
VECTOR2D b( double( a2.x ), double( a2.y ) );
|
||||
|
||||
VECTOR2D dir( b - a );
|
||||
dir = dir * ( extendLine / dir.SquaredEuclideanNorm() );
|
||||
|
||||
SHAPE_POLY_SET outline2 = *aOutline;
|
||||
outline2.Inflate( extendPoly, CORNER_STRATEGY::ROUND_ALL_CORNERS, 3 );
|
||||
|
||||
if( aTestLocalConcavity.first && !aOutline->Contains( a - dir, -1, 0 ) )
|
||||
return false;
|
||||
|
||||
if( aTestLocalConcavity.second && !aOutline->Contains( b + dir, -1, 0 ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
SEG segPath( a1, a2 );
|
||||
|
||||
if( aLayer != Edge_Cuts )
|
||||
{
|
||||
for( PCB_TRACK* track : aBoard.Tracks() )
|
||||
{
|
||||
if( !track )
|
||||
continue;
|
||||
|
||||
if( track->Type() == KICAD_T::PCB_TRACE_T && track->IsOnLayer( aLayer ) )
|
||||
{
|
||||
std::shared_ptr<SHAPE> sh = track->GetEffectiveShape();
|
||||
|
||||
if( sh && sh->Type() == SHAPE_TYPE::SH_SEGMENT )
|
||||
{
|
||||
SEG segTrack( track->GetStart(), track->GetEnd() );
|
||||
|
||||
if( segPath.Intersects( segTrack ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class GraphConnection;
|
||||
class GraphNode;
|
||||
class CreepageGraph;
|
||||
class CREEP_SHAPE;
|
||||
class BE_SHAPE;
|
||||
class BE_SHAPE_POINT;
|
||||
class BE_SHAPE_ARC;
|
||||
class BE_SHAPE_CIRCLE;
|
||||
class CU_SHAPE;
|
||||
class CU_SHAPE_SEGMENT;
|
||||
class CU_SHAPE_CIRCLE;
|
||||
class CU_SHAPE_ARC;
|
||||
|
||||
/** @class CREEP_SHAPE
|
||||
*
|
||||
* @brief A class used to represent the shapes for creepage calculation
|
||||
*/
|
||||
class CREEP_SHAPE
|
||||
{
|
||||
public:
|
||||
enum class TYPE
|
||||
{
|
||||
UNDEFINED = 0,
|
||||
POINT,
|
||||
CIRCLE,
|
||||
ARC
|
||||
};
|
||||
CREEP_SHAPE() {};
|
||||
|
||||
virtual ~CREEP_SHAPE() {}
|
||||
|
||||
|
||||
virtual int GetRadius() const { return 0; };
|
||||
virtual EDA_ANGLE GetStartAngle() const { return EDA_ANGLE( 0 ); };
|
||||
virtual EDA_ANGLE GetEndAngle() const { return EDA_ANGLE( 0 ); };
|
||||
virtual VECTOR2I GetStartPoint() const { return VECTOR2I( 0, 0 ); };
|
||||
virtual VECTOR2I GetEndPoint() const { return VECTOR2I( 0, 0 ); };
|
||||
VECTOR2I GetPos() const { return m_pos; };
|
||||
CREEP_SHAPE::TYPE GetType() const { return m_type; };
|
||||
const BOARD_ITEM* GetParent() const { return m_parent; };
|
||||
void SetParent( BOARD_ITEM* aParent ) { m_parent = aParent; };
|
||||
|
||||
virtual void ConnectChildren( GraphNode* a1, GraphNode* a2, CreepageGraph& aG ) const;
|
||||
|
||||
std::vector<path_connection> ReversePaths( const std::vector<path_connection>& aV ) const
|
||||
{
|
||||
std::vector<path_connection> r;
|
||||
r.reserve( aV.size() );
|
||||
|
||||
for( const auto& pc : aV )
|
||||
{
|
||||
r.emplace_back( pc );
|
||||
std::swap( r.back().a1, r.back().a2 );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
std::vector<path_connection> Paths( const CREEP_SHAPE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const
|
||||
{
|
||||
std::vector<path_connection> a;
|
||||
return a;
|
||||
};
|
||||
virtual std::vector<path_connection> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const
|
||||
{
|
||||
std::vector<path_connection> a;
|
||||
return a;
|
||||
};
|
||||
virtual std::vector<path_connection> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const
|
||||
{
|
||||
std::vector<path_connection> a;
|
||||
return a;
|
||||
};
|
||||
virtual std::vector<path_connection> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const
|
||||
{
|
||||
std::vector<path_connection> a;
|
||||
return a;
|
||||
};
|
||||
virtual std::vector<path_connection> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const
|
||||
{
|
||||
std::vector<path_connection> a;
|
||||
return a;
|
||||
};
|
||||
virtual std::vector<path_connection> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const
|
||||
{
|
||||
std::vector<path_connection> a;
|
||||
return a;
|
||||
};
|
||||
virtual std::vector<path_connection> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const
|
||||
{
|
||||
std::vector<path_connection> a;
|
||||
return a;
|
||||
};
|
||||
|
||||
//virtual std::vector<path_connection> GetPathsCuToBe( CREEP_SHAPE* aShape ) const{ std::vector<path_connection> a; return a;};
|
||||
bool IsConductive() { return m_conductive; };
|
||||
|
||||
|
||||
protected:
|
||||
bool m_conductive = false;
|
||||
BOARD_ITEM* m_parent = nullptr;
|
||||
VECTOR2I m_pos = VECTOR2I( 0, 0 );
|
||||
CREEP_SHAPE::TYPE m_type = CREEP_SHAPE::TYPE::UNDEFINED;
|
||||
};
|
||||
|
||||
|
||||
/** @class CU_SHAPE
|
||||
*
|
||||
* @brief Creepage: a conductive shape
|
||||
*/
|
||||
class CU_SHAPE : public CREEP_SHAPE
|
||||
{
|
||||
public:
|
||||
CU_SHAPE() : CREEP_SHAPE() { m_conductive = true; };
|
||||
};
|
||||
|
||||
/** @class BE_SHAPE
|
||||
*
|
||||
* @brief Creepage: a board edge shape
|
||||
*/
|
||||
class BE_SHAPE : public CREEP_SHAPE
|
||||
{
|
||||
public:
|
||||
BE_SHAPE() : CREEP_SHAPE() { m_conductive = false; };
|
||||
};
|
||||
|
||||
/** @class CU_SHAPE_SEGMENT
|
||||
*
|
||||
* @brief Creepage: a conductive segment
|
||||
*/
|
||||
class CU_SHAPE_SEGMENT : public CU_SHAPE
|
||||
{
|
||||
public:
|
||||
CU_SHAPE_SEGMENT( VECTOR2I aStart, VECTOR2I aEnd, double aWidth = 0 ) : CU_SHAPE()
|
||||
{
|
||||
m_start = aStart;
|
||||
m_end = aEnd;
|
||||
m_width = aWidth;
|
||||
}
|
||||
|
||||
VECTOR2I GetStart() const { return m_start; };
|
||||
VECTOR2I GetEnd() const { return m_end; };
|
||||
double GetWidth() const { return m_width; };
|
||||
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
|
||||
|
||||
private:
|
||||
VECTOR2I m_start = VECTOR2I( 0, 0 );
|
||||
VECTOR2I m_end = VECTOR2I( 0, 0 );
|
||||
double m_width = 0;
|
||||
};
|
||||
|
||||
/** @class CU_SHAPE_CIRCLE
|
||||
*
|
||||
* @brief Creepage: a conductive circle
|
||||
*/
|
||||
class CU_SHAPE_CIRCLE : public CU_SHAPE
|
||||
{
|
||||
public:
|
||||
CU_SHAPE_CIRCLE( VECTOR2I aPos, double aRadius = 0 ) : CU_SHAPE()
|
||||
{
|
||||
m_pos = aPos;
|
||||
m_radius = aRadius;
|
||||
}
|
||||
|
||||
VECTOR2I GetPos() const { return m_pos; };
|
||||
int GetRadius() const override { return m_radius; };
|
||||
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
|
||||
private:
|
||||
VECTOR2I m_pos = VECTOR2I( 0, 0 );
|
||||
double m_radius = 1;
|
||||
};
|
||||
|
||||
/** @class CU_SHAPE_ARC
|
||||
*
|
||||
* @brief Creepage: a conductive arc
|
||||
*/
|
||||
class CU_SHAPE_ARC : public CU_SHAPE_CIRCLE
|
||||
{
|
||||
public:
|
||||
CU_SHAPE_ARC( VECTOR2I aPos, double aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle,
|
||||
VECTOR2D aStartPoint, VECTOR2D aEndPoint ) : CU_SHAPE_CIRCLE( aPos, aRadius )
|
||||
{
|
||||
m_pos = aPos;
|
||||
m_type = CREEP_SHAPE::TYPE::ARC;
|
||||
m_startAngle = aStartAngle;
|
||||
m_endAngle = aEndAngle;
|
||||
m_startPoint = aStartPoint;
|
||||
m_endPoint = aEndPoint;
|
||||
m_radius = aRadius;
|
||||
}
|
||||
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
|
||||
|
||||
EDA_ANGLE GetStartAngle() const override { return m_startAngle; }
|
||||
EDA_ANGLE GetEndAngle() const override { return m_endAngle; }
|
||||
int GetRadius() const override { return m_radius; }
|
||||
|
||||
|
||||
VECTOR2I GetStartPoint() const override { return m_startPoint; }
|
||||
VECTOR2I GetEndPoint() const override { return m_endPoint; }
|
||||
EDA_ANGLE AngleBetweenStartAndEnd( const VECTOR2I aPoint ) const
|
||||
{
|
||||
EDA_ANGLE angle( aPoint - m_pos );
|
||||
while( angle < GetStartAngle() )
|
||||
angle += ANGLE_360;
|
||||
while( angle > GetEndAngle() + ANGLE_360 )
|
||||
angle -= ANGLE_360;
|
||||
|
||||
return angle;
|
||||
}
|
||||
double GetWidth() const { return m_width; };
|
||||
void SetWidth( double aW ) { m_width = aW; };
|
||||
|
||||
private:
|
||||
int m_width = 0;
|
||||
VECTOR2I m_pos = VECTOR2I( 0, 0 );
|
||||
double m_radius = 1;
|
||||
EDA_ANGLE m_startAngle = EDA_ANGLE( 0 );
|
||||
EDA_ANGLE m_endAngle = EDA_ANGLE( 180 );
|
||||
VECTOR2I m_startPoint = VECTOR2I( 1, 0 );
|
||||
VECTOR2I m_endPoint = VECTOR2I( -1, 0 );
|
||||
};
|
||||
|
||||
/** @class Graphnode
|
||||
*
|
||||
* @brief a node in a @class CreepageGraph
|
||||
*/
|
||||
class GraphNode
|
||||
{
|
||||
public:
|
||||
enum TYPE
|
||||
{
|
||||
|
||||
POINT = 0,
|
||||
CIRCLE,
|
||||
ARC,
|
||||
SEGMENT,
|
||||
VIRTUAL
|
||||
};
|
||||
|
||||
GraphNode( GraphNode::TYPE aType, CREEP_SHAPE* aParent, VECTOR2I aPos = VECTOR2I() )
|
||||
{
|
||||
m_parent = aParent;
|
||||
m_pos = aPos;
|
||||
m_type = aType;
|
||||
m_connectDirectly = true;
|
||||
m_connections = {};
|
||||
};
|
||||
|
||||
~GraphNode() {};
|
||||
|
||||
|
||||
CREEP_SHAPE* m_parent = nullptr;
|
||||
std::vector<GraphConnection*> m_connections = {};
|
||||
VECTOR2I m_pos = VECTOR2I( 0, 0 );
|
||||
// Virtual nodes are connected with a 0 weight connection to equivalent net ( same net or netclass )
|
||||
bool m_virtual = false;
|
||||
bool m_connectDirectly = true;
|
||||
int m_net = -1;
|
||||
|
||||
GraphNode::TYPE m_type;
|
||||
};
|
||||
|
||||
/** @class GraphConnection
|
||||
*
|
||||
* @brief a connection in a @class CreepageGraph
|
||||
*/
|
||||
class GraphConnection
|
||||
{
|
||||
public:
|
||||
GraphConnection( GraphNode* aN1, GraphNode* aN2, const path_connection& aPc ) :
|
||||
n1( aN1 ), n2( aN2 )
|
||||
{
|
||||
m_path = aPc;
|
||||
};
|
||||
|
||||
GraphNode* n1 = nullptr;
|
||||
GraphNode* n2 = nullptr;
|
||||
path_connection m_path;
|
||||
|
||||
std::vector<PCB_SHAPE> GetShapes();
|
||||
bool forceStraightLigne = false;
|
||||
};
|
||||
|
||||
|
||||
/** @class BE_SHAPE_POINT
|
||||
*
|
||||
* @brief Creepage: a board edge point
|
||||
*/
|
||||
class BE_SHAPE_POINT : public BE_SHAPE
|
||||
{
|
||||
public:
|
||||
BE_SHAPE_POINT( VECTOR2I aPos ) : BE_SHAPE()
|
||||
{
|
||||
m_pos = aPos;
|
||||
m_type = CREEP_SHAPE::TYPE::POINT;
|
||||
}
|
||||
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
}
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
|
||||
|
||||
void ConnectChildren( GraphNode* a1, GraphNode* a2, CreepageGraph& aG ) const override;
|
||||
};
|
||||
|
||||
/** @class BE_SHAPE_CIRCLE
|
||||
*
|
||||
* @brief Creepage: a board edge circle
|
||||
*/
|
||||
class BE_SHAPE_CIRCLE : public BE_SHAPE
|
||||
{
|
||||
public:
|
||||
BE_SHAPE_CIRCLE( VECTOR2I aPos = VECTOR2I( 0, 0 ), int aRadius = 0 ) : BE_SHAPE()
|
||||
{
|
||||
m_pos = aPos;
|
||||
m_radius = aRadius;
|
||||
m_type = CREEP_SHAPE::TYPE::CIRCLE;
|
||||
}
|
||||
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
|
||||
|
||||
int GetRadius() const override { return m_radius; }
|
||||
void ConnectChildren( GraphNode* a1, GraphNode* a2, CreepageGraph& aG ) const override;
|
||||
void ShortenChildDueToGV( GraphNode* a1, GraphNode* a2, CreepageGraph& aG,
|
||||
double aNormalWeight ) const;
|
||||
|
||||
|
||||
protected:
|
||||
int m_radius;
|
||||
};
|
||||
|
||||
/** @class BE_SHAPE_ARC
|
||||
*
|
||||
* @brief Creepage: a board edge arc
|
||||
*/
|
||||
class BE_SHAPE_ARC : public BE_SHAPE_CIRCLE
|
||||
{
|
||||
public:
|
||||
BE_SHAPE_ARC( VECTOR2I aPos, int aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle,
|
||||
VECTOR2D aStartPoint, VECTOR2D aEndPoint ) : BE_SHAPE_CIRCLE( aPos, aRadius )
|
||||
{
|
||||
m_type = CREEP_SHAPE::TYPE::ARC;
|
||||
m_startAngle = aStartAngle;
|
||||
m_endAngle = aEndAngle;
|
||||
m_startPoint = aStartPoint;
|
||||
m_endPoint = aEndPoint;
|
||||
m_radius = aRadius;
|
||||
}
|
||||
|
||||
void ConnectChildren( GraphNode* a1, GraphNode* a2, CreepageGraph& aG ) const override;
|
||||
|
||||
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
std::vector<path_connection> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override;
|
||||
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
std::vector<path_connection> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
|
||||
double aMaxSquaredWeight ) const override
|
||||
{
|
||||
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
|
||||
};
|
||||
|
||||
|
||||
EDA_ANGLE GetStartAngle() const override { return m_startAngle; }
|
||||
EDA_ANGLE GetEndAngle() const override { return m_endAngle; }
|
||||
int GetRadius() const override { return m_radius; }
|
||||
|
||||
|
||||
VECTOR2I GetStartPoint() const override { return m_startPoint; }
|
||||
VECTOR2I GetEndPoint() const override { return m_endPoint; }
|
||||
EDA_ANGLE AngleBetweenStartAndEnd( const VECTOR2I aPoint ) const
|
||||
{
|
||||
EDA_ANGLE angle( aPoint - m_pos );
|
||||
|
||||
while( angle < m_startAngle )
|
||||
angle += ANGLE_360;
|
||||
while( angle > m_endAngle + ANGLE_360 )
|
||||
angle -= ANGLE_360;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
std::pair<bool, bool> IsThereATangentPassingThroughPoint( const BE_SHAPE_POINT aPoint ) const;
|
||||
|
||||
protected:
|
||||
int m_radius;
|
||||
EDA_ANGLE m_startAngle;
|
||||
EDA_ANGLE m_endAngle;
|
||||
VECTOR2I m_startPoint;
|
||||
VECTOR2I m_endPoint;
|
||||
};
|
||||
|
||||
|
||||
/** @class CreepageGraph
|
||||
*
|
||||
* @brief A graph with nodes and connections for creepage calculation
|
||||
*/
|
||||
class CreepageGraph
|
||||
{
|
||||
public:
|
||||
CreepageGraph( BOARD& aBoard ) : m_board( aBoard )
|
||||
{
|
||||
m_boardOutline = nullptr;
|
||||
m_creepageTarget = -1;
|
||||
m_creepageTargetSquared = -1;
|
||||
};
|
||||
~CreepageGraph()
|
||||
{
|
||||
for( GraphConnection* gc : m_connections )
|
||||
{
|
||||
if( gc )
|
||||
{
|
||||
delete gc;
|
||||
gc = nullptr;
|
||||
}
|
||||
}
|
||||
for( GraphNode* gn : m_nodes )
|
||||
if( gn )
|
||||
{
|
||||
delete gn;
|
||||
gn = nullptr;
|
||||
}
|
||||
for( CREEP_SHAPE* cs : m_shapeCollection )
|
||||
if( cs )
|
||||
{
|
||||
delete cs;
|
||||
cs = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
BOARD& m_board;
|
||||
std::vector<BOARD_ITEM*> m_boardEdge;
|
||||
SHAPE_POLY_SET* m_boardOutline;
|
||||
|
||||
std::vector<GraphNode*> m_nodes;
|
||||
std::vector<GraphConnection*> m_connections;
|
||||
|
||||
|
||||
void TransformEdgeToCreepShapes();
|
||||
void TransformCreepShapesToNodes( std::vector<CREEP_SHAPE*>& aShapes );
|
||||
void RemoveDuplicatedShapes();
|
||||
// Add a node to the graph. If an equivalent node exists, returns the pointer of the existing node instead
|
||||
GraphNode* AddNode( GraphNode::TYPE aType, CREEP_SHAPE* aParent = nullptr,
|
||||
VECTOR2I aPos = VECTOR2I() );
|
||||
GraphNode* AddNodeVirtual();
|
||||
GraphConnection* AddConnection( GraphNode* aN1, GraphNode* aN2, const path_connection& aPc );
|
||||
GraphConnection* AddConnection( GraphNode* aN1, GraphNode* aN2 );
|
||||
GraphNode* FindNode( GraphNode::TYPE aType, CREEP_SHAPE* aParent, VECTOR2I aPos );
|
||||
|
||||
void RemoveConnection( GraphConnection*, bool aDelete = false );
|
||||
void Trim( double aWeightLimit );
|
||||
void Addshape( const SHAPE& aShape, GraphNode* aConnectTo = nullptr,
|
||||
BOARD_ITEM* aParent = nullptr );
|
||||
|
||||
double Solve( GraphNode* aFrom, GraphNode* aTo, std::vector<GraphConnection*>& aResult );
|
||||
|
||||
void GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer, bool aGenerateBoardEdges = true );
|
||||
GraphNode* AddNetElements( int aNetCode, PCB_LAYER_ID aLayer, int aMaxCreepage );
|
||||
|
||||
void SetTarget( double aTarget );
|
||||
double GetTarget() { return m_creepageTarget; };
|
||||
int m_minGrooveWidth = 0;
|
||||
|
||||
std::vector<CREEP_SHAPE*> m_shapeCollection;
|
||||
|
||||
private:
|
||||
double m_creepageTarget;
|
||||
double m_creepageTargetSquared;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -37,6 +37,8 @@
|
||||
class BOARD_COMMIT;
|
||||
class BOARD_DESIGN_SETTINGS;
|
||||
class DRC_TEST_PROVIDER;
|
||||
class DRC_TEST_PROVIDER_CLEARANCE_BASE;
|
||||
class DRC_TEST_PROVIDER_CREEPAGE;
|
||||
class PCB_EDIT_FRAME;
|
||||
class DS_PROXY_VIEW_ITEM;
|
||||
class BOARD_ITEM;
|
||||
@ -82,6 +84,10 @@ typedef std::function<void( const std::shared_ptr<DRC_ITEM>& aItem,
|
||||
*/
|
||||
class DRC_ENGINE : public UNITS_PROVIDER
|
||||
{
|
||||
// They need to change / restore the violation handler
|
||||
friend class DRC_TEST_PROVIDER_CLEARANCE_BASE;
|
||||
friend class DRC_TEST_PROVIDER_CREEPAGE;
|
||||
|
||||
public:
|
||||
DRC_ENGINE( BOARD* aBoard = nullptr, BOARD_DESIGN_SETTINGS* aSettings = nullptr );
|
||||
virtual ~DRC_ENGINE();
|
||||
|
144
pcbnew/drc/drc_test_provider_clearance_base.cpp
Normal file
144
pcbnew/drc/drc_test_provider_clearance_base.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com
|
||||
* Copyright (C) 2019-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 <drc/drc_test_provider_clearance_base.h>
|
||||
|
||||
void DRC_TEST_PROVIDER_CLEARANCE_BASE::ShowPathDRC( const std::vector<PCB_SHAPE>& aShapes,
|
||||
const VECTOR2I& aStart, const VECTOR2I& aEnd,
|
||||
int aLength )
|
||||
{
|
||||
COLOR_SETTINGS* colorSettings = new COLOR_SETTINGS( COLOR_SETTINGS::COLOR_BUILTIN_DEFAULT );
|
||||
COLOR_SETTINGS* defaultSettings = colorSettings->CreateBuiltinColorSettings()[0];
|
||||
COLOR4D errorColor = defaultSettings->GetColor( LAYER_DRC_ERROR );
|
||||
delete colorSettings;
|
||||
|
||||
std::vector<PCB_SHAPE> shortestPathShapes1, shortestPathShapes2;
|
||||
|
||||
// m_commit is protected and cannot be sent to the lambda function
|
||||
BOARD_COMMIT* aCommit = m_commit;
|
||||
|
||||
if( !m_commit )
|
||||
return;
|
||||
|
||||
// Add the path and its outlined area
|
||||
for( PCB_SHAPE sh : aShapes )
|
||||
{
|
||||
sh.SetStroke( false );
|
||||
sh.SetFilled( false );
|
||||
sh.SetLineColor( WHITE );
|
||||
shortestPathShapes1.push_back( sh );
|
||||
|
||||
sh.SetFilled( true );
|
||||
sh.SetFillColor( errorColor.WithAlpha( 0.5 ) );
|
||||
sh.SetWidth( aLength / 10 );
|
||||
shortestPathShapes2.push_back( sh );
|
||||
}
|
||||
|
||||
if( shortestPathShapes1.size() > 0 )
|
||||
{
|
||||
PCB_SHAPE s1, s2;
|
||||
s1.SetFilled( false );
|
||||
s2.SetFilled( false );
|
||||
VECTOR2I V1 = shortestPathShapes1[0].GetStart() - shortestPathShapes1[0].GetEnd();
|
||||
V1 = V1.Perpendicular().Resize( aLength / 30 );
|
||||
|
||||
s1.SetStart( aStart + V1 );
|
||||
s1.SetEnd( aStart - V1 );
|
||||
s1.SetWidth( 0 );
|
||||
s1.SetLineColor( WHITE );
|
||||
|
||||
|
||||
VECTOR2I V2 = shortestPathShapes1.back().GetStart() - shortestPathShapes1.back().GetEnd();
|
||||
V2 = V2.Perpendicular().Resize( aLength / 30 );
|
||||
|
||||
s2.SetStart( aEnd + V2 );
|
||||
s2.SetEnd( aEnd - V2 );
|
||||
s2.SetWidth( 0 );
|
||||
s2.SetLineColor( WHITE );
|
||||
|
||||
shortestPathShapes1.push_back( s1 );
|
||||
shortestPathShapes1.push_back( s2 );
|
||||
}
|
||||
|
||||
m_violationHandlerBuffer = [aCommit, shortestPathShapes1,
|
||||
shortestPathShapes2]( const std::shared_ptr<DRC_ITEM>& aItem,
|
||||
VECTOR2I aPos, int aReportLayer )
|
||||
{
|
||||
PCB_MARKER* marker = new PCB_MARKER( aItem, aPos, aReportLayer );
|
||||
|
||||
|
||||
if( !aCommit || !marker )
|
||||
return;
|
||||
|
||||
marker->SetShapes1( std::move( shortestPathShapes1 ) );
|
||||
marker->SetShapes2( std::move( shortestPathShapes2 ) );
|
||||
aCommit->Add( marker );
|
||||
};
|
||||
|
||||
std::swap( m_violationHandlerBuffer, m_drcEngine->m_violationHandler );
|
||||
}
|
||||
|
||||
|
||||
void DRC_TEST_PROVIDER_CLEARANCE_BASE::ReportAndShowPathCuToCu(
|
||||
std::shared_ptr<DRC_ITEM>& aDrce, const VECTOR2I& aMarkerPos, int aMarkerLayer,
|
||||
const BOARD_ITEM* aItem1, const BOARD_ITEM* aItem2, PCB_LAYER_ID layer, int aDistance )
|
||||
{
|
||||
CreepageGraph graph( *m_board );
|
||||
GraphNode* NetA = graph.AddNodeVirtual();
|
||||
GraphNode* NetB = graph.AddNodeVirtual();
|
||||
|
||||
// They need to be different or the algorithm won't compute the path.
|
||||
NetA->m_net = 1;
|
||||
NetB->m_net = 2;
|
||||
|
||||
graph.Addshape( *( aItem1->GetEffectiveShape( layer ) ), NetA, nullptr );
|
||||
graph.Addshape( *( aItem2->GetEffectiveShape( layer ) ), NetB, nullptr );
|
||||
|
||||
graph.GeneratePaths( aDistance * 2, layer );
|
||||
|
||||
double minValue = aDistance * 2;
|
||||
GraphConnection* minGc = nullptr;
|
||||
|
||||
for( GraphConnection* gc : graph.m_connections )
|
||||
{
|
||||
if( ( gc->m_path.weight < minValue ) && ( gc->m_path.weight > 0 ) )
|
||||
{
|
||||
minValue = gc->m_path.weight;
|
||||
minGc = gc;
|
||||
}
|
||||
}
|
||||
|
||||
if( minGc )
|
||||
{
|
||||
path_connection pc = minGc->m_path;
|
||||
ShowPathDRC( minGc->GetShapes(), pc.a1, pc.a2, aDistance );
|
||||
reportViolation( aDrce, aMarkerPos, aMarkerLayer );
|
||||
std::swap( m_violationHandlerBuffer, m_drcEngine->m_violationHandler );
|
||||
}
|
||||
else
|
||||
{
|
||||
reportViolation( aDrce, aMarkerPos, aMarkerLayer );
|
||||
}
|
||||
}
|
@ -28,6 +28,10 @@
|
||||
#define DRC_TEST_PROVIDER_CLEARANCE_BASE__H
|
||||
|
||||
#include <drc/drc_test_provider.h>
|
||||
#include <settings/color_settings.h>
|
||||
#include <drc/drc_engine.h>
|
||||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_creepage_utils.h>
|
||||
|
||||
class BOARD;
|
||||
|
||||
@ -49,6 +53,16 @@ public:
|
||||
protected:
|
||||
BOARD* m_board;
|
||||
bool m_boardOutlineValid;
|
||||
|
||||
void ReportAndShowPathCuToCu( std::shared_ptr<DRC_ITEM>& item, const VECTOR2I& aMarkerPos,
|
||||
int aMarkerLayer, const BOARD_ITEM* aItem1,
|
||||
const BOARD_ITEM* aItem2, PCB_LAYER_ID layer, int aDistance );
|
||||
|
||||
void ShowPathDRC( const std::vector<PCB_SHAPE>& aShapes, const VECTOR2I& aStart,
|
||||
const VECTOR2I& aEnd, int aLength );
|
||||
|
||||
|
||||
DRC_VIOLATION_HANDLER m_violationHandlerBuffer;
|
||||
};
|
||||
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_rule.h>
|
||||
#include <drc/drc_test_provider_clearance_base.h>
|
||||
#include <drc/drc_creepage_utils.h>
|
||||
#include <pcb_dimension.h>
|
||||
|
||||
#include <future>
|
||||
@ -290,7 +291,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_C
|
||||
drce->SetItems( item, other );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, pos, layer );
|
||||
ReportAndShowPathCuToCu( drce, pos, layer, item, other, layer, actual );
|
||||
has_error = true;
|
||||
|
||||
if( !m_drcEngine->GetReportAllTrackErrors() )
|
||||
@ -346,7 +347,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testSingleLayerItemAgainstItem( BOARD_C
|
||||
drce->SetItems( a[ii], b[ii] );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, pos, layer );
|
||||
ReportAndShowPathCuToCu( drce, pos, layer, a[ii], b[ii], layer, actual );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -462,8 +463,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||
drce->SetItems( aItem, aZone );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, pos, aLayer );
|
||||
ReportAndShowPathCuToCu( drce, pos, aLayer, aItem, aZone, aLayer, actual );
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,8 +501,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||
drce->SetItems( aItem, aZone );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, pos, aLayer );
|
||||
ReportAndShowPathCuToCu( drce, pos, aLayer, aItem, aZone, aLayer, actual );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -586,8 +585,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testKnockoutTextAgainstZone( BOARD_ITEM
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||
drce->SetItems( aText, aZone );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, pos, layer );
|
||||
ReportAndShowPathCuToCu( drce, pos, layer, aText, aZone, layer, actual );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -884,8 +882,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||
drce->SetItems( pad, other );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, pos, aLayer );
|
||||
ReportAndShowPathCuToCu( drce, pos, aLayer, pad, other, aLayer, actual );
|
||||
testHoles = false; // No need for multiple violations
|
||||
}
|
||||
}
|
||||
@ -916,8 +913,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||
drce->SetItems( pad, other );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, pos, aLayer );
|
||||
ReportAndShowPathCuToCu( drce, pos, aLayer, pad, other, aLayer, actual );
|
||||
testHoles = false; // No need for multiple violations
|
||||
}
|
||||
}
|
||||
@ -958,8 +954,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
||||
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
|
||||
drce->SetItems( pad, otherVia );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, pos, aLayer );
|
||||
ReportAndShowPathCuToCu( drce, pos, aLayer, pad, otherVia, aLayer, actual );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1413,8 +1408,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
|
||||
{
|
||||
drce->SetItems( zoneA, zoneB );
|
||||
drce->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drce, pt, layer );
|
||||
ReportAndShowPathCuToCu( drce, pt, layer, zoneA, zoneB, layer, actual );
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -74,6 +74,7 @@ const int GAL_LAYER_ORDER[] =
|
||||
LAYER_CONFLICTS_SHADOW,
|
||||
|
||||
LAYER_DRC_ERROR, LAYER_DRC_WARNING, LAYER_DRC_EXCLUSION, LAYER_MARKER_SHADOWS,
|
||||
LAYER_DRC_SHAPE1, LAYER_DRC_SHAPE2,
|
||||
LAYER_PAD_NETNAMES, LAYER_VIA_NETNAMES,
|
||||
Dwgs_User, ZONE_LAYER_FOR( Dwgs_User ),
|
||||
Cmts_User, ZONE_LAYER_FOR( Cmts_User ),
|
||||
@ -367,6 +368,7 @@ void PCB_DRAW_PANEL_GAL::SetHighContrastLayer( PCB_LAYER_ID aLayer )
|
||||
LAYER_VIA_THROUGH, LAYER_VIA_BBLIND, LAYER_VIA_MICROVIA, LAYER_VIA_HOLES,
|
||||
LAYER_VIA_HOLEWALLS,
|
||||
LAYER_DRC_ERROR, LAYER_DRC_WARNING, LAYER_DRC_EXCLUSION, LAYER_MARKER_SHADOWS,
|
||||
LAYER_DRC_SHAPE1, LAYER_DRC_SHAPE2,
|
||||
LAYER_SELECT_OVERLAY, LAYER_GP_OVERLAY,
|
||||
LAYER_RATSNEST, LAYER_CURSOR, LAYER_ANCHOR, LAYER_LOCKED_ITEM_SHADOW
|
||||
};
|
||||
@ -410,6 +412,7 @@ void PCB_DRAW_PANEL_GAL::SetTopLayer( PCB_LAYER_ID aLayer )
|
||||
LAYER_SELECT_OVERLAY, LAYER_GP_OVERLAY,
|
||||
LAYER_RATSNEST,
|
||||
LAYER_DRC_ERROR, LAYER_DRC_WARNING, LAYER_DRC_EXCLUSION, LAYER_MARKER_SHADOWS,
|
||||
LAYER_DRC_SHAPE1, LAYER_DRC_SHAPE2,
|
||||
LAYER_CONFLICTS_SHADOW
|
||||
};
|
||||
|
||||
@ -518,6 +521,8 @@ void PCB_DRAW_PANEL_GAL::SyncLayersVisibility( const BOARD* aBoard )
|
||||
m_view->SetLayerVisible( LAYER_SELECT_OVERLAY, true );
|
||||
m_view->SetLayerVisible( LAYER_RATSNEST, true );
|
||||
m_view->SetLayerVisible( LAYER_MARKER_SHADOWS, true );
|
||||
m_view->SetLayerVisible( LAYER_DRC_SHAPE1, true );
|
||||
m_view->SetLayerVisible( LAYER_DRC_SHAPE2, true );
|
||||
}
|
||||
|
||||
|
||||
@ -729,6 +734,10 @@ void PCB_DRAW_PANEL_GAL::setDefaultLayerDeps()
|
||||
m_view->SetLayerDisplayOnly( LAYER_DRC_EXCLUSION );
|
||||
m_view->SetLayerTarget( LAYER_MARKER_SHADOWS, KIGFX::TARGET_OVERLAY );
|
||||
m_view->SetLayerDisplayOnly( LAYER_MARKER_SHADOWS );
|
||||
m_view->SetLayerTarget( LAYER_DRC_SHAPE1, KIGFX::TARGET_OVERLAY );
|
||||
m_view->SetLayerDisplayOnly( LAYER_DRC_SHAPE1 );
|
||||
m_view->SetLayerTarget( LAYER_DRC_SHAPE2, KIGFX::TARGET_OVERLAY );
|
||||
m_view->SetLayerDisplayOnly( LAYER_DRC_SHAPE2 );
|
||||
|
||||
m_view->SetLayerTarget( LAYER_DRAWINGSHEET, KIGFX::TARGET_NONCACHED );
|
||||
m_view->SetLayerDisplayOnly( LAYER_DRAWINGSHEET ) ;
|
||||
|
@ -307,9 +307,11 @@ void PCB_MARKER::ViewGetLayers( int aLayers[], int& aCount ) const
|
||||
return;
|
||||
}
|
||||
|
||||
aCount = 2;
|
||||
aCount = 4;
|
||||
|
||||
aLayers[1] = LAYER_MARKER_SHADOWS;
|
||||
aLayers[2] = LAYER_DRC_SHAPE1;
|
||||
aLayers[3] = LAYER_DRC_SHAPE2;
|
||||
|
||||
switch( GetSeverity() )
|
||||
{
|
||||
@ -350,7 +352,7 @@ const BOX2I PCB_MARKER::GetBoundingBox() const
|
||||
{
|
||||
BOX2I box = GetBoundingBoxMarker();
|
||||
|
||||
for( auto& s : m_shapes )
|
||||
for( auto& s : m_shapes1 )
|
||||
box.Merge( s.GetBoundingBox() );
|
||||
|
||||
return box;
|
||||
|
@ -135,14 +135,17 @@ public:
|
||||
return wxT( "PCB_MARKER" );
|
||||
}
|
||||
|
||||
std::vector<PCB_SHAPE> GetShapes() const { return m_shapes; };
|
||||
std::vector<PCB_SHAPE> GetShapes1() const { return m_shapes1; };
|
||||
std::vector<PCB_SHAPE> GetShapes2() const { return m_shapes2; };
|
||||
|
||||
void SetShapes( const std::vector<PCB_SHAPE>& aShapes ) { m_shapes = aShapes; };
|
||||
void SetShapes1( const std::vector<PCB_SHAPE>& aShapes ) { m_shapes1 = aShapes; };
|
||||
void SetShapes2( const std::vector<PCB_SHAPE>& aShapes ) { m_shapes2 = aShapes; };
|
||||
|
||||
|
||||
protected:
|
||||
KIGFX::COLOR4D getColor() const override;
|
||||
std::vector<PCB_SHAPE> m_shapes;
|
||||
std::vector<PCB_SHAPE> m_shapes1; // Shown on LAYER_DRC_SHAPE1
|
||||
std::vector<PCB_SHAPE> m_shapes2; // Shown on LAYER_DRC_SHAPE2
|
||||
};
|
||||
|
||||
#endif // PCB_MARKER_H
|
||||
|
@ -2911,63 +2911,82 @@ void PCB_PAINTER::draw( const PCB_TARGET* aTarget )
|
||||
|
||||
void PCB_PAINTER::draw( const PCB_MARKER* aMarker, int aLayer )
|
||||
{
|
||||
bool isShadow = aLayer == LAYER_MARKER_SHADOWS;
|
||||
switch( aLayer )
|
||||
{
|
||||
case LAYER_MARKER_SHADOWS:
|
||||
case LAYER_DRC_ERROR:
|
||||
case LAYER_DRC_WARNING:
|
||||
{
|
||||
bool isShadow = aLayer == LAYER_MARKER_SHADOWS;
|
||||
|
||||
// Don't paint invisible markers.
|
||||
// It would be nice to do this through layer dependencies but we can't do an "or" there today
|
||||
if( aMarker->GetBoard() && !aMarker->GetBoard()->IsElementVisible( aMarker->GetColorLayer() ) )
|
||||
// Don't paint invisible markers.
|
||||
// It would be nice to do this through layer dependencies but we can't do an "or" there today
|
||||
if( aMarker->GetBoard()
|
||||
&& !aMarker->GetBoard()->IsElementVisible( aMarker->GetColorLayer() ) )
|
||||
return;
|
||||
|
||||
const_cast<PCB_MARKER*>( aMarker )->SetZoom( 1.0 / sqrt( m_gal->GetZoomFactor() ) );
|
||||
|
||||
SHAPE_LINE_CHAIN polygon;
|
||||
aMarker->ShapeToPolygon( polygon );
|
||||
|
||||
COLOR4D color = m_pcbSettings.GetColor( aMarker, isShadow ? LAYER_MARKER_SHADOWS
|
||||
: aMarker->GetColorLayer() );
|
||||
|
||||
m_gal->Save();
|
||||
m_gal->Translate( aMarker->GetPosition() );
|
||||
|
||||
if( isShadow )
|
||||
{
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetLineWidth( aMarker->MarkerScale() );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gal->SetFillColor( color );
|
||||
m_gal->SetIsFill( true );
|
||||
}
|
||||
|
||||
m_gal->DrawPolygon( polygon );
|
||||
m_gal->Restore();
|
||||
return;
|
||||
|
||||
const_cast<PCB_MARKER*>( aMarker )->SetZoom( 1.0 / sqrt( m_gal->GetZoomFactor() ) );
|
||||
|
||||
SHAPE_LINE_CHAIN polygon;
|
||||
aMarker->ShapeToPolygon( polygon );
|
||||
|
||||
COLOR4D color = m_pcbSettings.GetColor( aMarker, isShadow ? LAYER_MARKER_SHADOWS
|
||||
: aMarker->GetColorLayer() );
|
||||
|
||||
m_gal->Save();
|
||||
m_gal->Translate( aMarker->GetPosition() );
|
||||
|
||||
if( isShadow )
|
||||
}
|
||||
case LAYER_DRC_SHAPE1:
|
||||
case LAYER_DRC_SHAPE2:
|
||||
{
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetIsStroke( true );
|
||||
if( !aMarker->IsBrightened() )
|
||||
return;
|
||||
|
||||
int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns
|
||||
m_gal->SetLineWidth( aMarker->MarkerScale() );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gal->SetFillColor( color );
|
||||
m_gal->SetIsFill( true );
|
||||
}
|
||||
|
||||
m_gal->DrawPolygon( polygon );
|
||||
m_gal->Restore();
|
||||
|
||||
if( isShadow || ( aMarker->GetShapes().size() <= 0 ) )
|
||||
return; // Don't add shadow to shapes
|
||||
|
||||
// Show pat
|
||||
m_gal->SetIsFill( false );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetLineWidth( aMarker->MarkerScale() );
|
||||
|
||||
for( auto& shape : aMarker->GetShapes() )
|
||||
{
|
||||
switch( shape.GetShape() )
|
||||
for( auto& shape :
|
||||
aLayer == LAYER_DRC_SHAPE1 ? aMarker->GetShapes1() : aMarker->GetShapes2() )
|
||||
{
|
||||
case SHAPE_T::SEGMENT: m_gal->DrawSegment( shape.GetStart(), shape.GetEnd(), 0 ); break;
|
||||
case SHAPE_T::ARC:
|
||||
{
|
||||
EDA_ANGLE startAngle, endAngle;
|
||||
shape.CalcArcAngles( startAngle, endAngle );
|
||||
m_gal->DrawArc( shape.GetCenter(), shape.GetRadius(), startAngle, shape.GetArcAngle() );
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
m_gal->SetIsFill( shape.IsFilled() );
|
||||
m_gal->SetIsStroke( aLayer == LAYER_DRC_SHAPE1 ? true : false );
|
||||
m_gal->SetStrokeColor( shape.GetLineColor() );
|
||||
m_gal->SetFillColor( shape.GetFillColor() );
|
||||
|
||||
switch( shape.GetShape() )
|
||||
{
|
||||
case SHAPE_T::SEGMENT:
|
||||
m_gal->DrawSegment( shape.GetStart(), shape.GetEnd(), shape.GetWidth() );
|
||||
break;
|
||||
case SHAPE_T::ARC:
|
||||
{
|
||||
EDA_ANGLE startAngle, endAngle;
|
||||
shape.CalcArcAngles( startAngle, endAngle );
|
||||
m_gal->DrawArcSegment( shape.GetCenter(), shape.GetRadius(), startAngle,
|
||||
shape.GetArcAngle(), shape.GetWidth(), arc_to_seg_error );
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -185,6 +185,8 @@ void PCBNEW_PRINTOUT::setupViewLayers( KIGFX::VIEW& aView, const LSET& aLayerSet
|
||||
|
||||
setVisibility( LAYER_DRC_WARNING );
|
||||
setVisibility( LAYER_DRC_ERROR );
|
||||
setVisibility( LAYER_DRC_SHAPE1 );
|
||||
setVisibility( LAYER_DRC_SHAPE2 );
|
||||
setVisibility( LAYER_DRC_EXCLUSION );
|
||||
setVisibility( LAYER_ANCHOR );
|
||||
setVisibility( LAYER_DRAWINGSHEET );
|
||||
|
Loading…
Reference in New Issue
Block a user