7
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:
Fabien Corona 2024-10-21 15:56:12 +00:00
parent ab1b22d435
commit 07a0c980f3
16 changed files with 3507 additions and 3336 deletions

View File

@ -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" );

View File

@ -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 ) );

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View 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

View File

@ -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();

View 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 );
}
}

View File

@ -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;
};

View File

@ -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

View File

@ -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 ) ;

View File

@ -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;

View File

@ -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

View File

@ -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;
}
}
}
}
}

View File

@ -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 );