Add DRC warning for incorrectly mirrored text

This commit is contained in:
Dhineshkumar S 2024-12-08 05:00:38 +00:00 committed by Seth Hillbrand
parent d51c7372b4
commit 57127f7d12
9 changed files with 1100 additions and 1 deletions

View File

@ -285,6 +285,7 @@ set( PCBNEW_DRC_SRCS
drc/drc_test_provider_matched_length.cpp
drc/drc_test_provider_diff_pair_coupling.cpp
drc/drc_test_provider_sliver_checker.cpp
drc/drc_test_provider_text_mirroring.cpp
)
set( PCBNEW_NETLIST_SRCS

View File

@ -196,6 +196,9 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
m_DRCSeverities[ DRCE_CONNECTION_WIDTH ] = RPT_SEVERITY_WARNING;
m_DRCSeverities[DRCE_MIRRORED_TEXT_ON_FRONT_LAYER] = RPT_SEVERITY_WARNING;
m_DRCSeverities[DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER] = RPT_SEVERITY_WARNING;
m_MaxError = ARC_HIGH_DEF;
m_ZoneKeepExternalFillets = false;
m_UseHeightForLengthCalcs = true;

View File

@ -291,6 +291,14 @@ DRC_ITEM DRC_ITEM::footprintTHPadhasNoHole( DRCE_PAD_TH_WITH_NO_HOLE,
_( "Through hole pad has no hole" ),
wxT( "through_hole_pad_without_hole" ) );
DRC_ITEM DRC_ITEM::mirroredTextOnFrontLayer( DRCE_MIRRORED_TEXT_ON_FRONT_LAYER,
_( "Mirrored text on front layer" ),
wxT( "mirrored_text_on_front_layer" ) );
DRC_ITEM DRC_ITEM::nonMirroredTextOnBackLayer( DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER,
_( "Non-Mirrored text on back layer" ),
wxT( "nonmirrored_text_on_back_layer" ) );
std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes(
{
@ -433,6 +441,8 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
case DRCE_FOOTPRINT: return std::make_shared<DRC_ITEM>( footprint );
case DRCE_FOOTPRINT_TYPE_MISMATCH: return std::make_shared<DRC_ITEM>( footprintTypeMismatch );
case DRCE_PAD_TH_WITH_NO_HOLE: return std::make_shared<DRC_ITEM>( footprintTHPadhasNoHole );
case DRCE_MIRRORED_TEXT_ON_FRONT_LAYER: return std::make_shared<DRC_ITEM>( mirroredTextOnFrontLayer );
case DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER: return std::make_shared<DRC_ITEM>( nonMirroredTextOnBackLayer );
default:
wxFAIL_MSG( wxT( "Unknown DRC error code" ) );
return nullptr;

View File

@ -106,7 +106,10 @@ enum PCB_DRC_CODE {
DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE,
DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG,
DRCE_LAST = DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
DRCE_MIRRORED_TEXT_ON_FRONT_LAYER,
DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER,
DRCE_LAST = DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER
};
@ -236,6 +239,8 @@ private:
static DRC_ITEM footprint;
static DRC_ITEM footprintTypeMismatch;
static DRC_ITEM footprintTHPadhasNoHole;
static DRC_ITEM mirroredTextOnFrontLayer;
static DRC_ITEM nonMirroredTextOnBackLayer;
private:
DRC_RULE* m_violatingRule = nullptr;

View File

@ -0,0 +1,156 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021-2023 KiCad Developers.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <macros.h>
#include <pcb_field.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <drc/drc_engine.h>
#include <drc/drc_item.h>
#include <drc/drc_rule.h>
#include <drc/drc_test_provider.h>
#include <drc/drc_rtree.h>
#include <footprint.h>
/*
Text mirroring tests.
Errors generated:
- DRCE_MIRRORED_TEXT_ON_FRONT_LAYER
- DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER
*/
class DRC_TEST_PROVIDER_TEXT_MIRRORING : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_TEXT_MIRRORING()
{
}
virtual ~DRC_TEST_PROVIDER_TEXT_MIRRORING()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return wxT( "text_mirroring" );
};
virtual const wxString GetDescription() const override
{
return wxT( "Tests mirrored text on top layer and non-mirrored text on bottom layer" );
}
};
bool DRC_TEST_PROVIDER_TEXT_MIRRORING::Run()
{
if( m_drcEngine->IsErrorLimitExceeded( DRCE_MIRRORED_TEXT_ON_FRONT_LAYER )
&& m_drcEngine->IsErrorLimitExceeded( DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER ) )
{
reportAux( wxT( "Text mirroring violations ignored. Tests not run." ) );
return true; // continue with other tests
}
if( !reportPhase( _( "Checking text mirroring..." ) ) )
return false; // DRC cancelled
LSET topLayers( { F_Cu, F_SilkS, F_Mask, F_Fab } );
LSET bottomLayers( { B_Cu, B_SilkS, B_Mask, B_Fab } );
auto checkTextMirroring = [&]( BOARD_ITEM* item, EDA_TEXT* text, PCB_LAYER_ID layerId,
bool isMirrored, int errorCode ) -> bool
{
if( m_drcEngine->IsErrorLimitExceeded( errorCode ) )
return false;
bool layerMatch = ( isMirrored && topLayers.Contains( layerId ) )
|| ( !isMirrored && bottomLayers.Contains( layerId ) );
if( layerMatch && text->IsMirrored() == isMirrored )
{
auto drcItem = DRC_ITEM::Create( errorCode );
drcItem->SetErrorMessage( drcItem->GetErrorText() );
drcItem->SetItems( item );
reportViolation( drcItem, item->GetPosition(), layerId );
}
return true;
};
const int progressDelta = 250;
int count = 0;
int progressIndex = 0;
static const std::vector<KICAD_T> itemTypes = { PCB_FIELD_T, PCB_TEXT_T, PCB_TEXTBOX_T };
forEachGeometryItem( itemTypes, topLayers | bottomLayers,
[&]( BOARD_ITEM* item ) -> bool
{
++count;
return true;
} );
forEachGeometryItem( itemTypes, topLayers | bottomLayers,
[&]( BOARD_ITEM* item ) -> bool
{
if( !reportProgress( progressIndex++, count, progressDelta ) )
return false;
EDA_TEXT* text = nullptr;
switch( item->Type() )
{
case PCB_FIELD_T: text = static_cast<PCB_FIELD*>( item ); break;
case PCB_TEXT_T: text = static_cast<PCB_TEXT*>( item ); break;
case PCB_TEXTBOX_T: text = static_cast<PCB_TEXTBOX*>( item ); break;
default: UNIMPLEMENTED_FOR( item->GetClass() ); break;
}
if( !text || !text->IsVisible()
|| !m_drcEngine->GetBoard()->IsLayerEnabled( item->GetLayer() )
|| !m_drcEngine->GetBoard()->IsLayerVisible( item->GetLayer() ) )
return true;
if( !checkTextMirroring( item, text, item->GetLayer(), true, DRCE_MIRRORED_TEXT_ON_FRONT_LAYER ) ||
!checkTextMirroring( item, text, item->GetLayer(), false, DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER ) )
{
return false;
}
return true;
} );
reportRuleStatistics();
return !m_drcEngine->IsCancelled();
}
namespace detail
{
static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_TEXT_MIRRORING> dummy;
}

View File

@ -0,0 +1,167 @@
(kicad_pcb (version 20220914) (generator pcbnew)
(general
(thickness 1.026)
)
(paper "A3")
(layers
(0 "F.Cu" signal)
(1 "In1.Cu" signal)
(2 "In2.Cu" signal)
(31 "B.Cu" signal)
(34 "B.Paste" user)
(35 "F.Paste" user)
(36 "B.SilkS" user "B.Silkscreen")
(37 "F.SilkS" user "F.Silkscreen")
(38 "B.Mask" user)
(39 "F.Mask" user)
(40 "Dwgs.User" user "User.Drawings")
(41 "Cmts.User" user "User.Comments")
(42 "Eco1.User" user "User.Eco1")
(44 "Edge.Cuts" user)
(45 "Margin" user)
(46 "B.CrtYd" user "B.Courtyard")
(47 "F.CrtYd" user "F.Courtyard")
(48 "B.Fab" user)
(49 "F.Fab" user)
)
(setup
(stackup
(layer "F.SilkS" (type "Top Silk Screen") (color "White"))
(layer "F.Paste" (type "Top Solder Paste"))
(layer "F.Mask" (type "Top Solder Mask") (color "Green") (thickness 0.01))
(layer "F.Cu" (type "copper") (thickness 0.035))
(layer "dielectric 1" (type "prepreg") (thickness 0.3) (material "FR4") (epsilon_r 4.5) (loss_tangent 0.02))
(layer "In1.Cu" (type "copper") (thickness 0.018))
(layer "dielectric 2" (type "core") (thickness 0.3) (material "FR4") (epsilon_r 4.5) (loss_tangent 0.02))
(layer "In2.Cu" (type "copper") (thickness 0.018))
(layer "dielectric 3" (type "prepreg") (thickness 0.3) (material "FR4") (epsilon_r 4.5) (loss_tangent 0.02))
(layer "B.Cu" (type "copper") (thickness 0.035))
(layer "B.Mask" (type "Bottom Solder Mask") (color "Green") (thickness 0.01))
(layer "B.Paste" (type "Bottom Solder Paste"))
(layer "B.SilkS" (type "Bottom Silk Screen") (color "White"))
(copper_finish "ENIG")
(dielectric_constraints no)
)
(pad_to_mask_clearance 0)
(pcbplotparams
(layerselection 0x00010fc_ffffffff)
(plot_on_all_layers_selection 0x0001000_00000000)
(disableapertmacros false)
(usegerberextensions false)
(usegerberattributes true)
(usegerberadvancedattributes true)
(creategerberjobfile true)
(dashed_line_dash_ratio 12.000000)
(dashed_line_gap_ratio 3.000000)
(svgprecision 6)
(plotframeref false)
(viasonmask false)
(mode 1)
(useauxorigin false)
(hpglpennumber 1)
(hpglpenspeed 20)
(hpglpendiameter 15.000000)
(dxfpolygonmode true)
(dxfimperialunits true)
(dxfusepcbnewfont true)
(psnegative false)
(psa4output false)
(plotreference true)
(plotvalue true)
(plotinvisibletext false)
(sketchpadsonfab false)
(subtractmaskfromsilk false)
(outputformat 4)
(mirror false)
(drillshape 0)
(scaleselection 1)
(outputdirectory "production/")
)
)
(net 0 "")
(gr_rect (start 9.35 -61.4) (end 180.15 57)
(stroke (width 0.1) (type default)) (fill none) (layer "Edge.Cuts") (tstamp 911ca37d-8865-4202-a99f-e7891c2d16ae))
(gr_text "simple text 2" (at 16 -13) (layer "F.Cu") (tstamp 97394bf4-d910-49e0-bda6-baaca7842e99)
(effects (font (size 1.5 1.5) (thickness 0.25)) (justify left))
)
(gr_text "simple text 2" (at 89 -13) (layer "F.Cu") (tstamp ff95eb0d-ff5f-4a8d-a925-d60a05d1fff2)
(effects (font (size 1.5 1.5) (thickness 0.25)) (justify left mirror))
)
(gr_text "simple text 2" (at 71 31) (layer "B.Cu") (tstamp 18ca425a-3b7e-4cc7-8440-480d3042a171)
(effects (font (size 1.5 1.5) (thickness 0.25)) (justify left))
)
(gr_text "simple text 2" (at 32 29) (layer "B.Cu") (tstamp 790ffc06-45d7-4ed4-b045-d89e829d3135)
(effects (font (size 1.5 1.5) (thickness 0.25)) (justify left mirror))
)
(gr_text "simple text 1" (at 32 26) (layer "B.SilkS") (tstamp 7e3a2863-5a81-4d4a-8295-ed17226136f0)
(effects (font (size 1.5 1.5) (thickness 0.25)) (justify left mirror))
)
(gr_text "simple text 1" (at 71 28) (layer "B.SilkS") (tstamp 8cb8f7df-4caa-483a-b7a1-d40d95e631c7)
(effects (font (size 1.5 1.5) (thickness 0.25)) (justify left))
)
(gr_text "incorrect / false" (at 74 23) (layer "F.SilkS") (tstamp 3a0442d8-8f69-4fb3-85b5-b3ffb208ee62)
(effects (font (size 2 2) (thickness 0.3)) (justify left))
)
(gr_text "incorrect / false" (at 77 -22) (layer "F.SilkS") (tstamp 5527bae0-eadf-41e4-9a4e-e82e31eb71f8)
(effects (font (size 2 2) (thickness 0.3)) (justify left))
)
(gr_text "top layer (F.silkscreen / F.Cu)" (at 15 -30) (layer "F.SilkS") (tstamp 80b69f34-19f5-4535-aecf-df8f3e4851e1)
(effects (font (size 3 3) (thickness 0.3)) (justify left))
)
(gr_text "testboard for DRC:\n- mirrored text on top-layers\n- non-mirrored text on bottom layers" (at 15 -49) (layer "F.SilkS") (tstamp 8d9ea4cf-1047-42af-bf72-13258f22d6ad)
(effects (font (size 3 3) (thickness 0.3)) (justify left))
)
(gr_text "correct" (at 30 -22) (layer "F.SilkS") (tstamp a0f029bd-d330-447d-9dd4-6c9ea6600de6)
(effects (font (size 2 2) (thickness 0.3)) (justify left))
)
(gr_text "bottom layer (B.silkscreen / B.Cu)" (at 16 17) (layer "F.SilkS") (tstamp b506ef8d-4126-4569-a30b-5d5c63934176)
(effects (font (size 3 3) (thickness 0.3)) (justify left))
)
(gr_text "correct" (at 29 22) (layer "F.SilkS") (tstamp b620752b-4aab-48d8-8370-8770b56820e3)
(effects (font (size 2 2) (thickness 0.3)) (justify left))
)
(gr_text "simple text 1" (at 16 -16) (layer "F.SilkS") (tstamp dd26746f-af1a-449d-ae5e-a68117c99a23)
(effects (font (size 1.5 1.5) (thickness 0.25)) (justify left))
)
(gr_text "simple text 1" (at 89 -16) (layer "F.SilkS") (tstamp ec347ae7-892c-45b9-a6fe-fe03f0d9c93a)
(effects (font (size 1.5 1.5) (thickness 0.25)) (justify left mirror))
)
(gr_text_box "textbox 2\nmultiline"
(start 35 -10) (end 47 -4) (layer "F.Cu") (tstamp b37cbeb3-cc18-45c3-a18b-e035ed193e4b)
(effects (font (size 1 1) (thickness 0.25) bold) (justify left top))
(stroke (width 0.15) (type solid)) )
(gr_text_box "textbox 2\nmultiline"
(start 92 -10) (end 104 -4) (layer "F.Cu") (tstamp d129d2f4-9499-48b6-a0e8-0edf3c1f7c7f)
(effects (font (size 1 1) (thickness 0.25) bold) (justify left top mirror))
(stroke (width 0.15) (type solid)) )
(gr_text_box "textbox 2\nmultiline"
(start 35 32) (end 47 38) (layer "B.Cu") (tstamp 831c76a2-3beb-4d6b-b7c1-3175cb76a7e0)
(effects (font (size 1 1) (thickness 0.25) bold) (justify left top mirror))
(stroke (width 0.15) (type solid)) )
(gr_text_box "textbox 2\nmultiline"
(start 90 33) (end 102 39) (layer "B.Cu") (tstamp df9e4d96-b3a4-4674-9dba-7893ca08029d)
(effects (font (size 1 1) (thickness 0.25) bold) (justify left top))
(stroke (width 0.15) (type solid)) )
(gr_text_box "textbox 1"
(start 35 25) (end 47 31) (layer "B.SilkS") (tstamp a818a586-9ac1-47f6-963e-02014d41be0e)
(effects (font (size 1 1) (thickness 0.25) bold) (justify left top mirror))
(stroke (width 0.15) (type solid)) )
(gr_text_box "textbox 1"
(start 90 26) (end 102 32) (layer "B.SilkS") (tstamp fc05ddb3-8177-4e58-b8c6-b0abc62afc22)
(effects (font (size 1 1) (thickness 0.25) bold) (justify left top))
(stroke (width 0.15) (type solid)) )
(gr_text_box "textbox 1"
(start 92 -17) (end 104 -11) (layer "F.SilkS") (tstamp 2d1d2f60-3886-4d23-962a-ce37b181b02f)
(effects (font (size 1 1) (thickness 0.25) bold) (justify left top mirror))
(stroke (width 0.15) (type solid)) )
(gr_text_box "textbox 1"
(start 35 -17) (end 47 -11) (layer "F.SilkS") (tstamp 876b3d96-2106-4766-b75c-d8c618194c89)
(effects (font (size 1 1) (thickness 0.25) bold) (justify left top))
(stroke (width 0.15) (type solid)) )
)

View File

@ -0,0 +1,662 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"board_outline_line_width": 0.09999999999999999,
"copper_line_width": 0.19999999999999998,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.049999999999999996,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": false,
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.15,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.0,
"height": 0.6,
"width": 1.325
},
"silk_line_width": 0.15,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.3,
"silk_text_upright": false,
"zones": {
"45_degree_only": false,
"min_clearance": 0.39999999999999997
}
},
"diff_pair_dimensions": [
{
"gap": 0.0,
"via_gap": 0.0,
"width": 0.0
}
],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "ignore",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "error",
"lib_footprint_mismatch": "error",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "ignore",
"overlapping_pads": "warning",
"padstack": "error",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "ignore",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rules": {
"allow_blind_buried_vias": false,
"allow_microvias": true,
"max_error": 0.005,
"min_clearance": 0.09999999999999999,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.19999999999999998,
"min_hole_clearance": 0.19999999999999998,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.7999999999999999,
"min_text_thickness": 0.09999999999999999,
"min_through_hole_diameter": 0.19999999999999998,
"min_track_width": 0.15,
"min_via_annular_width": 0.15,
"min_via_diameter": 0.5,
"solder_mask_clearance": 0.0,
"solder_mask_min_width": 0.0,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 5,
"td_on_pad_in_zone": false,
"td_onpadsmd": true,
"td_onroundshapesonly": false,
"td_ontrackend": false,
"td_onviapad": true
}
],
"teardrop_parameters": [
{
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [
0.0,
0.15,
0.2,
0.3,
0.4,
0.5,
0.6,
0.8,
1.0
],
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
},
{
"diameter": 0.6,
"drill": 0.2
},
{
"diameter": 0.7,
"drill": 0.3
},
{
"diameter": 0.8,
"drill": 0.4
},
{
"diameter": 0.9,
"drill": 0.5
},
{
"diameter": 1.0,
"drill": 0.6
},
{
"diameter": 1.2,
"drill": 0.8
},
{
"diameter": 1.5,
"drill": 1.0
},
{
"diameter": 1.8,
"drill": 1.2
},
{
"diameter": 3.0,
"drill": 2.0
},
{
"diameter": 4.2,
"drill": 3.2
}
],
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"layer_presets": [
{
"activeLayer": -2,
"layers": [
0,
31,
36,
37,
40,
41,
42,
44,
45,
46,
47
],
"name": "standard_ohne_namen",
"renderLayers": [
125,
126,
127,
128,
129,
131,
133,
134,
135,
136,
137,
138,
139,
140,
141,
144,
145,
146,
147,
148,
149,
150,
151,
152,
153,
154,
155,
157,
158,
159,
160,
161
]
}
],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "ignore",
"pin_not_driven": "error",
"pin_to_pin": "error",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "DRC_mirrored text.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 6.0,
"clearance": 0.15,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.15,
"via_diameter": 0.5,
"via_drill": 0.2,
"wire_width": 6.0
},
{
"bus_width": 6.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "netclass_A",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
},
{
"bus_width": 6.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "netclass_B",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
},
{
"bus_width": 6.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "netclass_C",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
}
],
"meta": {
"version": 3
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"specctra_dsn": "",
"step": "Pumpenmodul_Kicad_v2_0g.step",
"vrml": ""
},
"page_layout_descr_file": "C:/Gewerbe/02_CAD/07_KiCAD/drc_rules_color_layersets/Zeichnungsblatt_kreuz_cross.kicad_wks"
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_bus_thickness": 12.0,
"default_junction_size": 36.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"default_wire_thickness": 6.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.3,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.3
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"ngspice": {
"fix_include_paths": true,
"fix_passive_vals": false,
"meta": {
"version": 0
},
"model_mode": 0,
"workbook_filename": ""
},
"page_layout_descr_file": "C:\\Gewerbe\\02_CAD\\07_KiCAD\\drc_rules_color_layersets\\pagelayout_default_ibfeew_logo.kicad_wks",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_external_command": "spice \"%I\"",
"spice_save_all_currents": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"9c65c6c4-f8a1-4869-9ee5-38624b40fdf6",
""
],
[
"bc4b8564-068d-4991-b14f-90e5d41e97f6",
"subsheet_01"
],
[
"cacb08af-0dee-43fe-b2d9-be9497e63672",
"subsheet_02"
],
[
"5f3dbbb3-f04b-4614-ae6d-a67190d1f34f",
"subsheet_03"
]
],
"text_variables": {}
}

View File

@ -63,6 +63,7 @@ set( QA_PCBNEW_SRCS
drc/test_drc_multi_netclasses.cpp
drc/test_drc_skew.cpp
drc/test_drc_component_classes.cpp
drc/test_drc_incorrect_text_mirror.cpp
pcb_io/altium/test_altium_rule_transformer.cpp
pcb_io/altium/test_altium_pcblib_import.cpp

View File

@ -0,0 +1,94 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 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 <qa_utils/wx_utils/unit_test_utils.h>
#include <pcbnew_utils/board_test_utils.h>
#include <board.h>
#include <board_design_settings.h>
#include <drc/drc_item.h>
#include <settings/settings_manager.h>
struct DRC_INCORRECT_TEXT_MIRROR_TEST_FIXTURE
{
DRC_INCORRECT_TEXT_MIRROR_TEST_FIXTURE() : m_settingsManager( true /* headless */ ) {}
SETTINGS_MANAGER m_settingsManager;
std::unique_ptr<BOARD> m_board;
};
BOOST_FIXTURE_TEST_CASE( DRCIncorrectTextMirror, DRC_INCORRECT_TEXT_MIRROR_TEST_FIXTURE )
{
std::vector<std::pair<wxString, int>> tests =
{
{ "incorrect_text_mirroring_drc", 8 }
};
for( const std::pair<wxString, int>& test : tests )
{
KI_TEST::LoadBoard( m_settingsManager, test.first, m_board );
KI_TEST::FillZones( m_board.get() );
std::vector<DRC_ITEM> violations;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
// Disable DRC tests not useful or not handled in this testcase
for( int ii = DRCE_FIRST; ii <= DRCE_LAST; ++ii )
bds.m_DRCSeverities[ii] = SEVERITY::RPT_SEVERITY_IGNORE;
// Ensure that our desired errors are fired
bds.m_DRCSeverities[DRCE_MIRRORED_TEXT_ON_FRONT_LAYER] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCSeverities[DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );
} );
bds.m_DRCEngine->RunTests( EDA_UNITS::MILLIMETRES, true, false );
if( violations.size() == test.second )
{
BOOST_CHECK_EQUAL( 1, 1 ); // quiet "did not check any assertions" warning
BOOST_TEST_MESSAGE( wxString::Format( "DRC incorrect text mirror test: %s, passed", test.first ) );
}
else
{
UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::INCHES );
std::map<KIID, EDA_ITEM*> itemMap;
m_board->FillItemMap( itemMap );
for( const DRC_ITEM& item : violations )
{
BOOST_TEST_MESSAGE( item.ShowReport( &unitsProvider, RPT_SEVERITY_ERROR, itemMap ) );
}
BOOST_ERROR( wxString::Format( "DRC incorrect text mirror test: %s, failed (violations found %d expected %d)",
test.first, (int)violations.size(), test.second ) );
}
}
}