Add SCH_RULE_AREA shapes to eeschema

Includes:
 - Fix GAL to draw closed polygons in eeschema
 - Add functionality to eeschema to draw arbitary polygons
 - Update polygon item previews to have customisable edge colour
 - Add new SCH_RULE_AREA class, derived from a poly SCH_SHAPE
 - Add SCH_RULE_AREA to paint and plot methods
 - Add new rule area color preference to themes
This commit is contained in:
James J 2024-04-25 14:24:46 +00:00 committed by Seth Hillbrand
parent da1926d723
commit be8744176c
57 changed files with 3860 additions and 112 deletions

View File

@ -374,6 +374,7 @@ static struct EDA_ITEM_DESC
.Map( SCH_LINE_T, _HKI( "Line" ) ) .Map( SCH_LINE_T, _HKI( "Line" ) )
.Map( SCH_BITMAP_T, _HKI( "Bitmap" ) ) .Map( SCH_BITMAP_T, _HKI( "Bitmap" ) )
.Map( SCH_SHAPE_T, _HKI( "Graphic" ) ) .Map( SCH_SHAPE_T, _HKI( "Graphic" ) )
.Map( SCH_RULE_AREA_T, _HKI( "Rule Area" ) )
.Map( SCH_TEXT_T, _HKI( "Text" ) ) .Map( SCH_TEXT_T, _HKI( "Text" ) )
.Map( SCH_TEXTBOX_T, _HKI( "Text Box" ) ) .Map( SCH_TEXTBOX_T, _HKI( "Text Box" ) )
.Map( SCH_TABLE_T, _HKI( "Table" ) ) .Map( SCH_TABLE_T, _HKI( "Table" ) )

View File

@ -122,6 +122,7 @@ wxString LayerName( int aLayer )
case LAYER_FIELDS: return _( "Symbol fields" ); case LAYER_FIELDS: return _( "Symbol fields" );
case LAYER_INTERSHEET_REFS: return _( "Sheet references" ); case LAYER_INTERSHEET_REFS: return _( "Sheet references" );
case LAYER_NETCLASS_REFS: return _( "Net class references" ); case LAYER_NETCLASS_REFS: return _( "Net class references" );
case LAYER_RULE_AREAS: return _( "Rule areas" );
case LAYER_DEVICE: return _( "Symbol body outlines" ); case LAYER_DEVICE: return _( "Symbol body outlines" );
case LAYER_DEVICE_BACKGROUND: return _( "Symbol body fills" ); case LAYER_DEVICE_BACKGROUND: return _( "Symbol body fills" );
case LAYER_NOTES: return _( "Schematic text && graphics" ); case LAYER_NOTES: return _( "Schematic text && graphics" );

View File

@ -33,6 +33,20 @@ const double POLYGON_ITEM::POLY_LINE_WIDTH = 1;
POLYGON_ITEM::POLYGON_ITEM() : POLYGON_ITEM::POLYGON_ITEM() :
SIMPLE_OVERLAY_ITEM() SIMPLE_OVERLAY_ITEM()
{ {
m_lineColor = KIGFX::COLOR4D::UNSPECIFIED;
m_leaderColor = KIGFX::COLOR4D::UNSPECIFIED;
}
void POLYGON_ITEM::SetLineColor( KIGFX::COLOR4D lineColor )
{
m_lineColor = lineColor;
}
void POLYGON_ITEM::SetLeaderColor( KIGFX::COLOR4D leaderColor )
{
m_leaderColor = leaderColor;
} }
@ -62,8 +76,13 @@ void POLYGON_ITEM::drawPreviewShape( KIGFX::VIEW* aView ) const
KIGFX::GAL& gal = *aView->GetGAL(); KIGFX::GAL& gal = *aView->GetGAL();
RENDER_SETTINGS* renderSettings = aView->GetPainter()->GetSettings(); RENDER_SETTINGS* renderSettings = aView->GetPainter()->GetSettings();
gal.SetIsStroke( true );
if( m_lockedChain.PointCount() >= 2 ) if( m_lockedChain.PointCount() >= 2 )
{ {
if( m_lineColor != KIGFX::COLOR4D::UNSPECIFIED )
gal.SetStrokeColor( m_lineColor );
gal.SetLineWidth( (float) aView->ToWorld( POLY_LINE_WIDTH ) ); gal.SetLineWidth( (float) aView->ToWorld( POLY_LINE_WIDTH ) );
gal.DrawPolyline( m_lockedChain ); gal.DrawPolyline( m_lockedChain );
} }
@ -71,7 +90,11 @@ void POLYGON_ITEM::drawPreviewShape( KIGFX::VIEW* aView ) const
// draw the leader line in a different color // draw the leader line in a different color
if( m_leaderChain.PointCount() >= 2 ) if( m_leaderChain.PointCount() >= 2 )
{ {
if( m_leaderColor != KIGFX::COLOR4D::UNSPECIFIED )
gal.SetStrokeColor( m_leaderColor );
else
gal.SetStrokeColor( renderSettings->GetLayerColor( LAYER_AUX_ITEMS ) ); gal.SetStrokeColor( renderSettings->GetLayerColor( LAYER_AUX_ITEMS ) );
gal.DrawPolyline( m_leaderChain ); gal.DrawPolyline( m_leaderChain );
} }

View File

@ -50,6 +50,7 @@ static const std::map<int, COLOR4D> s_defaultTheme =
{ LAYER_HIERLABEL, CSS_COLOR( 114, 86, 0, 1 ) }, { LAYER_HIERLABEL, CSS_COLOR( 114, 86, 0, 1 ) },
{ LAYER_LOCLABEL, CSS_COLOR( 15, 15, 15, 1 ) }, { LAYER_LOCLABEL, CSS_COLOR( 15, 15, 15, 1 ) },
{ LAYER_NETCLASS_REFS, CSS_COLOR( 72, 72, 72, 1 ) }, { LAYER_NETCLASS_REFS, CSS_COLOR( 72, 72, 72, 1 ) },
{ LAYER_RULE_AREAS, CSS_COLOR( 255, 0, 0, 1 ) },
{ LAYER_NOCONNECT, CSS_COLOR( 0, 0, 132, 1 ) }, { LAYER_NOCONNECT, CSS_COLOR( 0, 0, 132, 1 ) },
{ LAYER_NOTES, CSS_COLOR( 0, 0, 194, 1 ) }, { LAYER_NOTES, CSS_COLOR( 0, 0, 194, 1 ) },
{ LAYER_PRIVATE_NOTES, CSS_COLOR( 72, 72, 255, 1 ) }, { LAYER_PRIVATE_NOTES, CSS_COLOR( 72, 72, 255, 1 ) },
@ -268,6 +269,7 @@ static const std::map<int, COLOR4D> s_classicTheme =
{ LAYER_HIERLABEL, COLOR4D( BROWN ) }, { LAYER_HIERLABEL, COLOR4D( BROWN ) },
{ LAYER_LOCLABEL, COLOR4D( BLACK ) }, { LAYER_LOCLABEL, COLOR4D( BLACK ) },
{ LAYER_NETCLASS_REFS, COLOR4D( BLACK ) }, { LAYER_NETCLASS_REFS, COLOR4D( BLACK ) },
{ LAYER_RULE_AREAS, COLOR4D( RED ) },
{ LAYER_NOCONNECT, COLOR4D( BLUE ) }, { LAYER_NOCONNECT, COLOR4D( BLUE ) },
{ LAYER_NOTES, COLOR4D( LIGHTBLUE ) }, { LAYER_NOTES, COLOR4D( LIGHTBLUE ) },
{ LAYER_PRIVATE_NOTES, COLOR4D( LIGHTBLUE ) }, { LAYER_PRIVATE_NOTES, COLOR4D( LIGHTBLUE ) },

View File

@ -75,6 +75,7 @@ COLOR_SETTINGS::COLOR_SETTINGS( const wxString& aFilename, bool aAbsolutePath )
CLR( "schematic.label_hier", LAYER_HIERLABEL ); CLR( "schematic.label_hier", LAYER_HIERLABEL );
CLR( "schematic.label_local", LAYER_LOCLABEL ); CLR( "schematic.label_local", LAYER_LOCLABEL );
CLR( "schematic.netclass_flag", LAYER_NETCLASS_REFS ); CLR( "schematic.netclass_flag", LAYER_NETCLASS_REFS );
CLR( "schematic.rule_area", LAYER_RULE_AREAS );
CLR( "schematic.no_connect", LAYER_NOCONNECT ); CLR( "schematic.no_connect", LAYER_NOCONNECT );
CLR( "schematic.note", LAYER_NOTES ); CLR( "schematic.note", LAYER_NOTES );
CLR( "schematic.private_note", LAYER_PRIVATE_NOTES ); CLR( "schematic.private_note", LAYER_PRIVATE_NOTES );

View File

@ -383,6 +383,7 @@ set( EESCHEMA_SRCS
sch_render_settings.cpp sch_render_settings.cpp
sch_screen.cpp sch_screen.cpp
sch_shape.cpp sch_shape.cpp
sch_rule_area.cpp
sch_sheet.cpp sch_sheet.cpp
sch_sheet_path.cpp sch_sheet_path.cpp
sch_sheet_pin.cpp sch_sheet_pin.cpp
@ -431,6 +432,7 @@ set( EESCHEMA_SRCS
tools/ee_point_editor.cpp tools/ee_point_editor.cpp
tools/ee_selection.cpp tools/ee_selection.cpp
tools/ee_selection_tool.cpp tools/ee_selection_tool.cpp
tools/rule_area_create_helper.cpp
tools/sch_drawing_tools.cpp tools/sch_drawing_tools.cpp
tools/sch_edit_table_tool.cpp tools/sch_edit_table_tool.cpp
tools/sch_edit_tool.cpp tools/sch_edit_tool.cpp

View File

@ -36,6 +36,7 @@
#include <sch_line.h> #include <sch_line.h>
#include <sch_marker.h> #include <sch_marker.h>
#include <sch_pin.h> #include <sch_pin.h>
#include <sch_rule_area.h>
#include <sch_sheet.h> #include <sch_sheet.h>
#include <sch_sheet_path.h> #include <sch_sheet_path.h>
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
@ -430,10 +431,35 @@ const wxString& CONNECTION_SUBGRAPH::GetNameForDriver( SCH_ITEM* aItem ) const
} }
const wxString CONNECTION_SUBGRAPH::GetNetclassForDriver( SCH_ITEM* aItem ) const const std::vector<std::pair<wxString, SCH_ITEM*>>
CONNECTION_SUBGRAPH::GetNetclassesForDriver( SCH_ITEM* aItem, bool returnAll ) const
{ {
wxString netclass; std::vector<std::pair<wxString, SCH_ITEM*>> foundNetclasses;
const std::unordered_set<SCH_RULE_AREA*>& ruleAreaCache = aItem->GetRuleAreaCache();
// Get netclasses on attached rule areas
for( SCH_RULE_AREA* ruleArea : ruleAreaCache )
{
const std::vector<std::pair<wxString, SCH_ITEM*>> ruleNetclasses =
ruleArea->GetResolvedNetclasses();
if( ruleNetclasses.size() > 0 )
{
if( returnAll )
{
foundNetclasses.insert( foundNetclasses.end(), ruleNetclasses.begin(),
ruleNetclasses.end() );
}
else
{
foundNetclasses.push_back( ruleNetclasses[0] );
return foundNetclasses;
}
}
}
// Get netclasses on child fields
aItem->RunOnChildren( aItem->RunOnChildren(
[&]( SCH_ITEM* aChild ) [&]( SCH_ITEM* aChild )
{ {
@ -443,15 +469,19 @@ const wxString CONNECTION_SUBGRAPH::GetNetclassForDriver( SCH_ITEM* aItem ) cons
if( field->GetCanonicalName() == wxT( "Netclass" ) ) if( field->GetCanonicalName() == wxT( "Netclass" ) )
{ {
netclass = field->GetText(); wxString netclass = field->GetText();
return false;
if( netclass != wxEmptyString )
foundNetclasses.push_back( { field->GetText(), aItem } );
return returnAll;
} }
} }
return true; return true;
} ); } );
return netclass; return foundNetclasses;
} }
@ -742,7 +772,9 @@ void CONNECTION_GRAPH::Recalculate( const SCH_SHEET_LIST& aSheetList, bool aUnco
} }
else if( item->Type() == SCH_SHEET_T ) else if( item->Type() == SCH_SHEET_T )
{ {
for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() ) SCH_SHEET* sheetItem = static_cast<SCH_SHEET*>( item );
for( SCH_SHEET_PIN* pin : sheetItem->GetPins() )
{ {
if( pin->IsConnectivityDirty() ) if( pin->IsConnectivityDirty() )
{ {
@ -2347,11 +2379,15 @@ void CONNECTION_GRAPH::buildConnectionGraph( std::function<void( SCH_ITEM* )>* a
{ {
for( SCH_ITEM* item : subgraph->m_items ) for( SCH_ITEM* item : subgraph->m_items )
{ {
netclass = subgraph->GetNetclassForDriver( item ); const std::vector<std::pair<wxString, SCH_ITEM*>> netclassesWithProviders =
subgraph->GetNetclassesForDriver( item, false );
if( !netclass.IsEmpty() ) if( netclassesWithProviders.size() > 0 )
{
netclass = netclassesWithProviders[0].first;
break; break;
} }
}
if( !netclass.IsEmpty() ) if( !netclass.IsEmpty() )
{ {
@ -3188,40 +3224,52 @@ bool CONNECTION_GRAPH::ercCheckNetclassConflicts( const std::vector<CONNECTION_S
wxString firstNetclass; wxString firstNetclass;
SCH_ITEM* firstNetclassDriver = nullptr; SCH_ITEM* firstNetclassDriver = nullptr;
const SCH_SHEET_PATH* firstNetclassDriverSheet = nullptr; const SCH_SHEET_PATH* firstNetclassDriverSheet = nullptr;
bool conflictFound = false;
for( const CONNECTION_SUBGRAPH* subgraph : subgraphs ) for( const CONNECTION_SUBGRAPH* subgraph : subgraphs )
{ {
for( SCH_ITEM* item : subgraph->m_items ) for( SCH_ITEM* item : subgraph->m_items )
{ {
const wxString netclass = subgraph->GetNetclassForDriver( item ); const std::vector<std::pair<wxString, SCH_ITEM*>> netclassesWithProvider =
subgraph->GetNetclassesForDriver( item, true );
if( netclass.IsEmpty() ) if( netclassesWithProvider.size() == 0 )
continue; continue;
if( netclass != firstNetclass ) auto checkNetclass = [&]( const std::pair<wxString, SCH_ITEM*>& netclass )
{
if( netclass.first != firstNetclass )
{ {
if( !firstNetclassDriver ) if( !firstNetclassDriver )
{ {
firstNetclass = netclass; firstNetclass = netclass.first;
firstNetclassDriver = item; firstNetclassDriver = netclass.second;
firstNetclassDriverSheet = &subgraph->GetSheet(); firstNetclassDriverSheet = &subgraph->GetSheet();
continue;
} }
else
{
conflictFound = true;
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NETCLASS_CONFLICT ); std::shared_ptr<ERC_ITEM> ercItem =
ercItem->SetItems( firstNetclassDriver, item ); ERC_ITEM::Create( ERCE_NETCLASS_CONFLICT );
ercItem->SetItems( firstNetclassDriver, netclass.second );
ercItem->SetSheetSpecificPath( subgraph->GetSheet() ); ercItem->SetSheetSpecificPath( subgraph->GetSheet() );
ercItem->SetItemsSheetPaths( *firstNetclassDriverSheet, subgraph->GetSheet() ); ercItem->SetItemsSheetPaths( *firstNetclassDriverSheet,
subgraph->GetSheet() );
SCH_MARKER* marker = new SCH_MARKER( ercItem, item->GetPosition() ); SCH_MARKER* marker =
new SCH_MARKER( ercItem, netclass.second->GetPosition() );
subgraph->m_sheet.LastScreen()->Append( marker ); subgraph->m_sheet.LastScreen()->Append( marker );
return false;
} }
} }
};
for( const std::pair<wxString, SCH_ITEM*>& netclass : netclassesWithProvider )
checkNetclass( netclass );
}
} }
return true; return conflictFound;
} }

View File

@ -23,6 +23,7 @@
#define _CONNECTION_GRAPH_H #define _CONNECTION_GRAPH_H
#include <mutex> #include <mutex>
#include <utility>
#include <vector> #include <vector>
#include <erc_settings.h> #include <erc_settings.h>
@ -122,7 +123,12 @@ public:
/// Return the candidate net name for a driver. /// Return the candidate net name for a driver.
const wxString& GetNameForDriver( SCH_ITEM* aItem ) const; const wxString& GetNameForDriver( SCH_ITEM* aItem ) const;
const wxString GetNetclassForDriver( SCH_ITEM* aItem ) const; /// Return the resolved netclasses for the item, and the source item providing the netclass
/// @param aItem the item to query for netclass assignments
/// @param returnAll If true, return all assigned netclasses (for ERC). If false, stop on first
/// netclass (for connectivity).
const std::vector<std::pair<wxString, SCH_ITEM*>>
GetNetclassesForDriver( SCH_ITEM* aItem, bool returnAll ) const;
/// Combine another subgraph on the same sheet into this one. /// Combine another subgraph on the same sheet into this one.
void Absorb( CONNECTION_SUBGRAPH* aOther ); void Absorb( CONNECTION_SUBGRAPH* aOther );

View File

@ -51,7 +51,8 @@ const std::vector<KICAD_T> EE_COLLECTOR::EditableItems = {
SCH_BITMAP_T, SCH_BITMAP_T,
SCH_LINE_T, SCH_LINE_T,
SCH_BUS_WIRE_ENTRY_T, SCH_BUS_WIRE_ENTRY_T,
SCH_JUNCTION_T SCH_JUNCTION_T,
SCH_RULE_AREA_T
}; };
@ -76,7 +77,8 @@ const std::vector<KICAD_T> EE_COLLECTOR::MovableItems =
SCH_FIELD_T, SCH_FIELD_T,
SCH_SYMBOL_T, SCH_SYMBOL_T,
SCH_SHEET_PIN_T, SCH_SHEET_PIN_T,
SCH_SHEET_T SCH_SHEET_T,
SCH_RULE_AREA_T
}; };

View File

@ -41,6 +41,7 @@
#include <sch_edit_frame.h> #include <sch_edit_frame.h>
#include <sch_marker.h> #include <sch_marker.h>
#include <sch_reference_list.h> #include <sch_reference_list.h>
#include <sch_rule_area.h>
#include <sch_sheet.h> #include <sch_sheet.h>
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
#include <sch_textbox.h> #include <sch_textbox.h>
@ -1229,6 +1230,73 @@ int ERC_TESTER::TestSimModelIssues()
} }
int ERC_TESTER::RunRuleAreaERC()
{
int numErrors = 0;
ERC_SETTINGS& settings = m_schematic->ErcSettings();
if( !settings.IsTestEnabled( ERCE_OVERLAPPING_RULE_AREAS ) )
return 0;
std::map<SCH_SCREEN*, std::vector<SCH_RULE_AREA*>> allScreenRuleAreas;
SCH_SCREENS screens( m_schematic->Root() );
for( SCH_SCREEN* screen = screens.GetFirst(); screen != nullptr; screen = screens.GetNext() )
{
for( SCH_ITEM* item : screen->Items().OfType( SCH_RULE_AREA_T ) )
{
allScreenRuleAreas[screen].push_back( static_cast<SCH_RULE_AREA*>( item ) );
}
}
if( settings.IsTestEnabled( ERCE_OVERLAPPING_RULE_AREAS ) )
numErrors += TestRuleAreaOverlappingRuleAreasERC( allScreenRuleAreas );
return numErrors;
}
int ERC_TESTER::TestRuleAreaOverlappingRuleAreasERC(
std::map<SCH_SCREEN*, std::vector<SCH_RULE_AREA*>>& allScreenRuleAreas )
{
int numErrors = 0;
for( auto screenRuleAreas : allScreenRuleAreas )
{
std::vector<SCH_RULE_AREA*>& ruleAreas = screenRuleAreas.second;
for( std::size_t i = 0; i < ruleAreas.size(); ++i )
{
SHAPE_POLY_SET& polyFirst = ruleAreas[i]->GetPolyShape();
for( std::size_t j = i + 1; j < ruleAreas.size(); ++j )
{
SHAPE_POLY_SET polySecond = ruleAreas[j]->GetPolyShape();
if( polyFirst.Collide( &polySecond ) )
{
numErrors++;
SCH_SCREEN* screen = screenRuleAreas.first;
SCH_SHEET_PATH firstSheet = screen->GetClientSheetPaths()[0];
std::shared_ptr<ERC_ITEM> ercItem =
ERC_ITEM::Create( ERCE_OVERLAPPING_RULE_AREAS );
ercItem->SetItems( ruleAreas[i], ruleAreas[j] );
ercItem->SetSheetSpecificPath( firstSheet );
ercItem->SetItemsSheetPaths( firstSheet, firstSheet );
SCH_MARKER* marker = new SCH_MARKER( ercItem, ruleAreas[i]->GetPosition() );
screen->Append( marker );
}
}
}
}
return numErrors;
}
void ERC_TESTER::RunTests( DS_PROXY_VIEW_ITEM* aDrawingSheet, SCH_EDIT_FRAME* aEditFrame, void ERC_TESTER::RunTests( DS_PROXY_VIEW_ITEM* aDrawingSheet, SCH_EDIT_FRAME* aEditFrame,
KIFACE* aCvPcb, PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter ) KIFACE* aCvPcb, PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter )
{ {
@ -1267,6 +1335,14 @@ void ERC_TESTER::RunTests( DS_PROXY_VIEW_ITEM* aDrawingSheet, SCH_EDIT_FRAME* aE
m_schematic->ConnectionGraph()->RunERC(); m_schematic->ConnectionGraph()->RunERC();
if( aProgressReporter )
aProgressReporter->AdvancePhase( _( "Checking rule areas..." ) );
if( settings.IsTestEnabled( ERCE_OVERLAPPING_RULE_AREAS ) )
{
RunRuleAreaERC();
}
if( aProgressReporter ) if( aProgressReporter )
aProgressReporter->AdvancePhase( _( "Checking units..." ) ); aProgressReporter->AdvancePhase( _( "Checking units..." ) );

View File

@ -27,6 +27,8 @@
#define ERC_H #define ERC_H
#include <erc_settings.h> #include <erc_settings.h>
#include <vector>
#include <map>
class SCH_SHEET_LIST; class SCH_SHEET_LIST;
@ -36,6 +38,8 @@ class SCH_EDIT_FRAME;
class PROGRESS_REPORTER; class PROGRESS_REPORTER;
struct KIFACE; struct KIFACE;
class PROJECT; class PROJECT;
class SCREEN;
class SCH_RULE_AREA;
extern const wxString CommentERC_H[]; extern const wxString CommentERC_H[];
@ -141,6 +145,17 @@ public:
*/ */
int TestMissingNetclasses(); int TestMissingNetclasses();
/**
* Tests for rule area ERC issues
*/
int RunRuleAreaERC();
/**
* Runs ERC to check for overlapping rule areas
*/
int TestRuleAreaOverlappingRuleAreasERC(
std::map<SCH_SCREEN*, std::vector<SCH_RULE_AREA*>>& allScreenRuleAreas );
void RunTests( DS_PROXY_VIEW_ITEM* aDrawingSheet, SCH_EDIT_FRAME* aEditFrame, void RunTests( DS_PROXY_VIEW_ITEM* aDrawingSheet, SCH_EDIT_FRAME* aEditFrame,
KIFACE* aCvPcb, PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter ); KIFACE* aCvPcb, PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter );

View File

@ -119,6 +119,10 @@ ERC_ITEM ERC_ITEM::netclassConflict( ERCE_NETCLASS_CONFLICT,
_( "Conflicting netclass assignments" ), _( "Conflicting netclass assignments" ),
wxT( "conflicting_netclasses" ) ); wxT( "conflicting_netclasses" ) );
ERC_ITEM ERC_ITEM::overlappingRuleAreas( ERCE_OVERLAPPING_RULE_AREAS,
_( "Overlapping rule areas" ),
wxT( "overlapping_rule_areas" ) );
ERC_ITEM ERC_ITEM::netNotBusMember( ERCE_BUS_ENTRY_CONFLICT, ERC_ITEM ERC_ITEM::netNotBusMember( ERCE_BUS_ENTRY_CONFLICT,
_( "Net is graphically connected to a bus but not a bus member" ), _( "Net is graphically connected to a bus but not a bus member" ),
wxT( "net_not_bus_member" ) ); wxT( "net_not_bus_member" ) );
@ -239,7 +243,8 @@ std::vector<std::reference_wrapper<RC_ITEM>> ERC_ITEM::allItemTypes( {
ERC_ITEM::missingUnits, ERC_ITEM::missingUnits,
ERC_ITEM::missingInputPin, ERC_ITEM::missingInputPin,
ERC_ITEM::missingBidiPin, ERC_ITEM::missingBidiPin,
ERC_ITEM::missingPowerInputPin ERC_ITEM::missingPowerInputPin,
ERC_ITEM::overlappingRuleAreas
} ); } );
@ -269,6 +274,7 @@ std::shared_ptr<ERC_ITEM> ERC_ITEM::Create( int aErrorCode )
case ERCE_BUS_TO_BUS_CONFLICT: return std::make_shared<ERC_ITEM>( busToBusConflict ); case ERCE_BUS_TO_BUS_CONFLICT: return std::make_shared<ERC_ITEM>( busToBusConflict );
case ERCE_BUS_TO_NET_CONFLICT: return std::make_shared<ERC_ITEM>( busToNetConflict ); case ERCE_BUS_TO_NET_CONFLICT: return std::make_shared<ERC_ITEM>( busToNetConflict );
case ERCE_NETCLASS_CONFLICT: return std::make_shared<ERC_ITEM>( netclassConflict ); case ERCE_NETCLASS_CONFLICT: return std::make_shared<ERC_ITEM>( netclassConflict );
case ERCE_OVERLAPPING_RULE_AREAS: return std::make_shared<ERC_ITEM>( overlappingRuleAreas );
case ERCE_GLOBLABEL: return std::make_shared<ERC_ITEM>( globalLabelDangling ); case ERCE_GLOBLABEL: return std::make_shared<ERC_ITEM>( globalLabelDangling );
case ERCE_UNRESOLVED_VARIABLE: return std::make_shared<ERC_ITEM>( unresolvedVariable ); case ERCE_UNRESOLVED_VARIABLE: return std::make_shared<ERC_ITEM>( unresolvedVariable );
case ERCE_UNDEFINED_NETCLASS: return std::make_shared<ERC_ITEM>( undefinedNetclass ); case ERCE_UNDEFINED_NETCLASS: return std::make_shared<ERC_ITEM>( undefinedNetclass );

View File

@ -202,6 +202,7 @@ private:
static ERC_ITEM busDefinitionConflict; static ERC_ITEM busDefinitionConflict;
static ERC_ITEM multipleNetNames; static ERC_ITEM multipleNetNames;
static ERC_ITEM netclassConflict; static ERC_ITEM netclassConflict;
static ERC_ITEM overlappingRuleAreas;
static ERC_ITEM netNotBusMember; static ERC_ITEM netNotBusMember;
static ERC_ITEM busToBusConflict; static ERC_ITEM busToBusConflict;
static ERC_ITEM busToNetConflict; static ERC_ITEM busToNetConflict;

View File

@ -67,6 +67,7 @@ enum ERCE_T
ERCE_BUS_TO_NET_CONFLICT, ///< A bus wire is graphically connected to a net port/pin ERCE_BUS_TO_NET_CONFLICT, ///< A bus wire is graphically connected to a net port/pin
///< (or vice versa). ///< (or vice versa).
ERCE_NETCLASS_CONFLICT, ///< Multiple labels assign different netclasses to same net. ERCE_NETCLASS_CONFLICT, ///< Multiple labels assign different netclasses to same net.
ERCE_OVERLAPPING_RULE_AREAS, ///< Rule areas are overlapping
ERCE_GLOBLABEL, ///< A global label is unique. ERCE_GLOBLABEL, ///< A global label is unique.
ERCE_UNRESOLVED_VARIABLE, ///< A text variable could not be resolved. ERCE_UNRESOLVED_VARIABLE, ///< A text variable could not be resolved.
ERCE_UNDEFINED_NETCLASS, ///< A netclass was referenced but not defined. ERCE_UNDEFINED_NETCLASS, ///< A netclass was referenced but not defined.

View File

@ -248,8 +248,9 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
placeMenu->Add( EE_ACTIONS::placeNoConnect ); placeMenu->Add( EE_ACTIONS::placeNoConnect );
placeMenu->Add( EE_ACTIONS::placeJunction ); placeMenu->Add( EE_ACTIONS::placeJunction );
placeMenu->Add( EE_ACTIONS::placeLabel ); placeMenu->Add( EE_ACTIONS::placeLabel );
placeMenu->Add( EE_ACTIONS::placeClassLabel );
placeMenu->Add( EE_ACTIONS::placeGlobalLabel ); placeMenu->Add( EE_ACTIONS::placeGlobalLabel );
placeMenu->Add( EE_ACTIONS::placeClassLabel );
placeMenu->Add( EE_ACTIONS::drawRuleArea );
placeMenu->AppendSeparator(); placeMenu->AppendSeparator();
placeMenu->Add( EE_ACTIONS::placeHierLabel ); placeMenu->Add( EE_ACTIONS::placeHierLabel );

View File

@ -221,10 +221,9 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
} ); } );
} }
auto updateConnectivityFlag = auto updateConnectivityFlag = [&]()
[&]()
{ {
if( schItem->IsConnectable() ) if( schItem->IsConnectable() || ( schItem->Type() == SCH_RULE_AREA_T ) )
{ {
dirtyConnectivity = true; dirtyConnectivity = true;
@ -318,8 +317,11 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
if( frame ) if( frame )
currentSheet = frame->GetCurrentSheet(); currentSheet = frame->GetCurrentSheet();
if( itemCopy->HasConnectivityChanges( schItem, &currentSheet ) ) if( itemCopy->HasConnectivityChanges( schItem, &currentSheet )
|| ( itemCopy->Type() == SCH_RULE_AREA_T ) )
{
updateConnectivityFlag(); updateConnectivityFlag();
}
undoList.PushItem( itemWrapper ); undoList.PushItem( itemWrapper );
ent.m_copy = nullptr; // We've transferred ownership to the undo list ent.m_copy = nullptr; // We've transferred ownership to the undo list

View File

@ -22,6 +22,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <algorithm>
#include <api/api_handler_sch.h> #include <api/api_handler_sch.h>
#include <api/api_server.h> #include <api/api_server.h>
#include <base_units.h> #include <base_units.h>
@ -36,6 +37,7 @@
#include <eeschema_id.h> #include <eeschema_id.h>
#include <executable_names.h> #include <executable_names.h>
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
#include <geometry/shape_segment.h>
#include <gestfich.h> #include <gestfich.h>
#include <dialogs/html_message_box.h> #include <dialogs/html_message_box.h>
#include <core/ignore.h> #include <core/ignore.h>
@ -59,6 +61,7 @@
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
#include <schematic.h> #include <schematic.h>
#include <sch_commit.h> #include <sch_commit.h>
#include <sch_rule_area.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <advanced_config.h> #include <advanced_config.h>
#include <sim/simulator_frame.h> #include <sim/simulator_frame.h>
@ -85,6 +88,7 @@
#include <tools/sch_move_tool.h> #include <tools/sch_move_tool.h>
#include <tools/sch_navigate_tool.h> #include <tools/sch_navigate_tool.h>
#include <tools/sch_find_replace_tool.h> #include <tools/sch_find_replace_tool.h>
#include <unordered_set>
#include <view/view_controls.h> #include <view/view_controls.h>
#include <widgets/wx_infobar.h> #include <widgets/wx_infobar.h>
#include <widgets/hierarchy_pane.h> #include <widgets/hierarchy_pane.h>
@ -756,6 +760,7 @@ void SCH_EDIT_FRAME::setupUIConditions()
CURRENT_TOOL( EE_ACTIONS::placeClassLabel ); CURRENT_TOOL( EE_ACTIONS::placeClassLabel );
CURRENT_TOOL( EE_ACTIONS::placeGlobalLabel ); CURRENT_TOOL( EE_ACTIONS::placeGlobalLabel );
CURRENT_TOOL( EE_ACTIONS::placeHierLabel ); CURRENT_TOOL( EE_ACTIONS::placeHierLabel );
CURRENT_TOOL( EE_ACTIONS::drawRuleArea );
CURRENT_TOOL( EE_ACTIONS::drawSheet ); CURRENT_TOOL( EE_ACTIONS::drawSheet );
CURRENT_TOOL( EE_ACTIONS::placeSheetPin ); CURRENT_TOOL( EE_ACTIONS::placeSheetPin );
CURRENT_TOOL( EE_ACTIONS::syncSheetPins ); CURRENT_TOOL( EE_ACTIONS::syncSheetPins );
@ -1763,52 +1768,150 @@ void SCH_EDIT_FRAME::RecalculateConnections( SCH_COMMIT* aCommit, SCH_CLEANUP_FL
if( !ADVANCED_CFG::GetCfg().m_IncrementalConnectivity || aCleanupFlags == GLOBAL_CLEANUP if( !ADVANCED_CFG::GetCfg().m_IncrementalConnectivity || aCleanupFlags == GLOBAL_CLEANUP
|| m_undoList.m_CommandsList.empty() ) || m_undoList.m_CommandsList.empty() )
{ {
// Update all rule areas so we can cascade implied connectivity changes
std::unordered_set<SCH_SCREEN*> all_screens;
for( const SCH_SHEET_PATH& path : list )
all_screens.insert( path.LastScreen() );
SCH_RULE_AREA::UpdateRuleAreasInScreens( all_screens, GetCanvas()->GetView() );
// Recalculate all connectivity
Schematic().ConnectionGraph()->Recalculate( list, true, &changeHandler ); Schematic().ConnectionGraph()->Recalculate( list, true, &changeHandler );
} }
else else
{ {
struct CHANGED_ITEM
{
SCH_ITEM* item;
SCH_ITEM* linked_item;
SCH_SCREEN* screen;
};
PICKED_ITEMS_LIST* changed_list = m_undoList.m_CommandsList.back(); PICKED_ITEMS_LIST* changed_list = m_undoList.m_CommandsList.back();
// Final change sets
std::set<SCH_ITEM*> changed_items; std::set<SCH_ITEM*> changed_items;
std::set<VECTOR2I> pts; std::set<VECTOR2I> pts;
std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> item_paths; std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> item_paths;
for( unsigned ii = 0; ii < changed_list->GetCount(); ++ii ) // Working change sets
std::unordered_set<SCH_SCREEN*> changed_screens;
std::set<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>> changed_rule_areas;
std::vector<CHANGED_ITEM> changed_connectable_items;
// Lambda to add an item to the connectivity update sets
auto addItemToChangeSet =
[&changed_items, &pts, &item_paths, &changed_screens]( CHANGED_ITEM itemData )
{ {
SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( changed_list->GetPickedItem( ii ) ); SCH_SHEET_PATHS& paths = itemData.screen->GetClientSheetPaths();
// Ignore objects that are not connectable. std::vector<VECTOR2I> tmp_pts = itemData.item->GetConnectionPoints();
if( !item || !item->IsConnectable() )
continue;
SCH_SCREEN* screen = static_cast<SCH_SCREEN*>( changed_list->GetScreenForItem( ii ) );
SCH_SHEET_PATHS& paths = screen->GetClientSheetPaths();
std::vector<VECTOR2I> tmp_pts = item->GetConnectionPoints();
pts.insert( tmp_pts.begin(), tmp_pts.end() ); pts.insert( tmp_pts.begin(), tmp_pts.end() );
changed_items.insert( item ); changed_items.insert( itemData.item );
for( SCH_SHEET_PATH& path : paths ) for( SCH_SHEET_PATH& path : paths )
item_paths.insert( std::make_pair( path, item ) ); item_paths.insert( std::make_pair( path, itemData.item ) );
item = dynamic_cast<SCH_ITEM*>( changed_list->GetPickedItemLink( ii ) ); if( !itemData.linked_item || !itemData.linked_item->IsConnectable() )
return;
if( !item || !item->IsConnectable() ) tmp_pts = itemData.linked_item->GetConnectionPoints();
continue;
tmp_pts = item->GetConnectionPoints();
pts.insert( tmp_pts.begin(), tmp_pts.end() ); pts.insert( tmp_pts.begin(), tmp_pts.end() );
changed_items.insert( item ); changed_items.insert( itemData.linked_item );
// We have to directly add the pins here because the link may not exist on the schematic // We have to directly add the pins here because the link may not exist on the schematic
// anymore and so won't be picked up by GetScreen()->Items().Overlapping() below. // anymore and so won't be picked up by GetScreen()->Items().Overlapping() below.
if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item ) ) if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( itemData.linked_item ) )
{ {
std::vector<SCH_PIN*> pins = symbol->GetPins(); std::vector<SCH_PIN*> pins = symbol->GetPins();
changed_items.insert( pins.begin(), pins.end() ); changed_items.insert( pins.begin(), pins.end() );
} }
for( SCH_SHEET_PATH& path : paths ) for( SCH_SHEET_PATH& path : paths )
item_paths.insert( std::make_pair( path, item ) ); item_paths.insert( std::make_pair( path, itemData.linked_item ) );
};
// Get all changed connectable items and determine all changed screens
for( unsigned ii = 0; ii < changed_list->GetCount(); ++ii )
{
SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( changed_list->GetPickedItem( ii ) );
if( item )
{
SCH_SCREEN* screen =
static_cast<SCH_SCREEN*>( changed_list->GetScreenForItem( ii ) );
changed_screens.insert( screen );
if( item->Type() == SCH_RULE_AREA_T )
{
SCH_RULE_AREA* ruleArea = static_cast<SCH_RULE_AREA*>( item );
// Clear item and directive associations for this rule area
ruleArea->ResetDirectivesAndItems( GetCanvas()->GetView() );
changed_rule_areas.insert( { ruleArea, screen } );
}
else if( item->IsConnectable() )
{
SCH_ITEM* linked_item =
dynamic_cast<SCH_ITEM*>( changed_list->GetPickedItemLink( ii ) );
changed_connectable_items.push_back( { item, linked_item, screen } );
}
}
}
// Update rule areas in changed screens to propagate any directive connectivity changes
std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>> forceUpdateRuleAreas =
SCH_RULE_AREA::UpdateRuleAreasInScreens( changed_screens, GetCanvas()->GetView() );
std::for_each( forceUpdateRuleAreas.begin(), forceUpdateRuleAreas.end(),
[&]( std::pair<SCH_RULE_AREA*, SCH_SCREEN*>& updatedRuleArea )
{
changed_rule_areas.insert( updatedRuleArea );
} );
// If a SCH_RULE_AREA was changed, we need to add all past and present contained items to
// update their connectivity
for( const std::pair<SCH_RULE_AREA*, SCH_SCREEN*>& changedRuleArea : changed_rule_areas )
{
for( SCH_ITEM* containedItem :
changedRuleArea.first->GetPastAndPresentContainedItems() )
{
addItemToChangeSet( { containedItem, nullptr, changedRuleArea.second } );
}
}
// Add all changed items, and associated items, to the change set
for( CHANGED_ITEM& changed_item_data : changed_connectable_items )
{
addItemToChangeSet( changed_item_data );
// If a SCH_DIRECTIVE_LABEL was changed which is attached to a SCH_RULE_AREA, we need
// to add the contained items to the change set to force update of their connectivity
if( changed_item_data.item->Type() == SCH_DIRECTIVE_LABEL_T )
{
const std::vector<VECTOR2I> labelConnectionPoints =
changed_item_data.item->GetConnectionPoints();
EE_RTREE::EE_TYPE candidateRuleAreas =
changed_item_data.screen->Items().Overlapping(
SCH_RULE_AREA_T, changed_item_data.item->GetBoundingBox() );
for( SCH_ITEM* candidateRuleArea : candidateRuleAreas )
{
SCH_RULE_AREA* ruleArea = static_cast<SCH_RULE_AREA*>( candidateRuleArea );
std::vector<SHAPE*> borderShapes = ruleArea->MakeEffectiveShapes( true );
if( ruleArea->GetPolyShape().CollideEdge( labelConnectionPoints[0], nullptr,
5 ) )
{
for( SCH_ITEM* containedItem : ruleArea->GetPastAndPresentContainedItems() )
addItemToChangeSet(
{ containedItem, nullptr, changed_item_data.screen } );
}
}
}
} }
for( const VECTOR2I& pt: pts ) for( const VECTOR2I& pt: pts )

View File

@ -103,4 +103,5 @@
//#define SEXPR_SCHEMATIC_FILE_VERSION 20230808 // Move Sim.Enable field to exclude_from_sim attr //#define SEXPR_SCHEMATIC_FILE_VERSION 20230808 // Move Sim.Enable field to exclude_from_sim attr
//#define SEXPR_SCHEMATIC_FILE_VERSION 20230819 // Allow multiple library symbol inheritance depth. //#define SEXPR_SCHEMATIC_FILE_VERSION 20230819 // Allow multiple library symbol inheritance depth.
//#define SEXPR_SCHEMATIC_FILE_VERSION 20231120 // generator_version; V8 cleanups //#define SEXPR_SCHEMATIC_FILE_VERSION 20231120 // generator_version; V8 cleanups
#define SEXPR_SCHEMATIC_FILE_VERSION 20240101 // Tables. //#define SEXPR_SCHEMATIC_FILE_VERSION 20240101 // Tables.
#define SEXPR_SCHEMATIC_FILE_VERSION 20240417 // Rule areas

View File

@ -42,6 +42,7 @@
#include <sch_pin.h> #include <sch_pin.h>
#include <sch_shape.h> #include <sch_shape.h>
#include <sch_no_connect.h> #include <sch_no_connect.h>
#include <sch_rule_area.h>
#include <sch_text.h> #include <sch_text.h>
#include <sch_textbox.h> #include <sch_textbox.h>
#include <sch_table.h> #include <sch_table.h>
@ -471,6 +472,10 @@ void SCH_IO_KICAD_SEXPR::Format( SCH_SHEET* aSheet )
saveShape( static_cast<SCH_SHAPE*>( item ), 1 ); saveShape( static_cast<SCH_SHAPE*>( item ), 1 );
break; break;
case SCH_RULE_AREA_T:
saveRuleArea( static_cast<SCH_RULE_AREA*>( item ), 1 );
break;
case SCH_TEXT_T: case SCH_TEXT_T:
case SCH_LABEL_T: case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T: case SCH_GLOBAL_LABEL_T:
@ -599,6 +604,10 @@ void SCH_IO_KICAD_SEXPR::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSele
saveShape( static_cast<SCH_SHAPE*>( item ), 0 ); saveShape( static_cast<SCH_SHAPE*>( item ), 0 );
break; break;
case SCH_RULE_AREA_T:
saveRuleArea( static_cast<SCH_RULE_AREA*>( item ), 0 );
break;
case SCH_TEXT_T: case SCH_TEXT_T:
case SCH_LABEL_T: case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T: case SCH_GLOBAL_LABEL_T:
@ -1234,6 +1243,16 @@ void SCH_IO_KICAD_SEXPR::saveShape( SCH_SHAPE* aShape, int aNestLevel )
} }
void SCH_IO_KICAD_SEXPR::saveRuleArea( SCH_RULE_AREA* aRuleArea, int aNestLevel )
{
wxCHECK_RET( aRuleArea != nullptr && m_out != nullptr, "" );
m_out->Print( aNestLevel, "(rule_area " );
saveShape( aRuleArea, aNestLevel + 1 );
m_out->Print( aNestLevel, ")\n" );
}
void SCH_IO_KICAD_SEXPR::saveLine( SCH_LINE* aLine, int aNestLevel ) void SCH_IO_KICAD_SEXPR::saveLine( SCH_LINE* aLine, int aNestLevel )
{ {
wxCHECK_RET( aLine != nullptr && m_out != nullptr, "" ); wxCHECK_RET( aLine != nullptr && m_out != nullptr, "" );

View File

@ -43,6 +43,7 @@ class SCH_JUNCTION;
class SCH_NO_CONNECT; class SCH_NO_CONNECT;
class SCH_LINE; class SCH_LINE;
class SCH_SHAPE; class SCH_SHAPE;
class SCH_RULE_AREA;
class SCH_BUS_ENTRY_BASE; class SCH_BUS_ENTRY_BASE;
class SCH_TEXT; class SCH_TEXT;
class SCH_TEXTBOX; class SCH_TEXTBOX;
@ -151,6 +152,7 @@ private:
void saveBusEntry( SCH_BUS_ENTRY_BASE* aBusEntry, int aNestLevel ); void saveBusEntry( SCH_BUS_ENTRY_BASE* aBusEntry, int aNestLevel );
void saveLine( SCH_LINE* aLine, int aNestLevel ); void saveLine( SCH_LINE* aLine, int aNestLevel );
void saveShape( SCH_SHAPE* aShape, int aNestLevel ); void saveShape( SCH_SHAPE* aShape, int aNestLevel );
void saveRuleArea( SCH_RULE_AREA* aRuleArea, int aNestLevel );
void saveText( SCH_TEXT* aText, int aNestLevel ); void saveText( SCH_TEXT* aText, int aNestLevel );
void saveTextBox( SCH_TEXTBOX* aText, int aNestLevel ); void saveTextBox( SCH_TEXTBOX* aText, int aNestLevel );
void saveTable( SCH_TABLE* aTable, int aNestLevel ); void saveTable( SCH_TABLE* aTable, int aNestLevel );

View File

@ -46,6 +46,7 @@
#include <sch_edit_frame.h> // SYM_ORIENT_XXX #include <sch_edit_frame.h> // SYM_ORIENT_XXX
#include <sch_field.h> #include <sch_field.h>
#include <sch_line.h> #include <sch_line.h>
#include <sch_rule_area.h>
#include <sch_textbox.h> #include <sch_textbox.h>
#include <sch_table.h> #include <sch_table.h>
#include <sch_tablecell.h> #include <sch_tablecell.h>
@ -2745,6 +2746,10 @@ void SCH_IO_KICAD_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet, bool aIsCopya
screen->Append( parseSchBezier() ); screen->Append( parseSchBezier() );
break; break;
case T_rule_area:
screen->Append( parseSchRuleArea() );
break;
case T_netclass_flag: // present only during early development of 7.0 case T_netclass_flag: // present only during early development of 7.0
KI_FALLTHROUGH; KI_FALLTHROUGH;
@ -2782,7 +2787,7 @@ void SCH_IO_KICAD_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet, bool aIsCopya
default: default:
Expecting( "symbol, paper, page, title_block, bitmap, sheet, junction, no_connect, " Expecting( "symbol, paper, page, title_block, bitmap, sheet, junction, no_connect, "
"bus_entry, line, bus, text, label, class_label, global_label, " "bus_entry, line, bus, text, label, class_label, global_label, "
"hierarchical_label, symbol_instances, or bus_alias" ); "hierarchical_label, symbol_instances, rule_area, or bus_alias" );
} }
} }
@ -3927,6 +3932,43 @@ SCH_SHAPE* SCH_IO_KICAD_SEXPR_PARSER::parseSchRectangle()
} }
SCH_RULE_AREA* SCH_IO_KICAD_SEXPR_PARSER::parseSchRuleArea()
{
wxCHECK_MSG( CurTok() == T_rule_area, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a rule area." ) );
T token;
STROKE_PARAMS stroke( schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS ), LINE_STYLE::DEFAULT );
FILL_PARAMS fill;
std::unique_ptr<SCH_RULE_AREA> ruleArea = std::make_unique<SCH_RULE_AREA>();
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_polyline:
{
std::unique_ptr<SCH_SHAPE> poly( parseSchPolyLine() );
ruleArea->SetPolyShape( poly->GetPolyShape() );
ruleArea->SetStroke( poly->GetStroke() );
ruleArea->SetFillMode( poly->GetFillMode() );
ruleArea->SetFillColor( poly->GetFillColor() );
break;
}
default:
Expecting( "polyline" );
}
}
return ruleArea.release();
}
SCH_SHAPE* SCH_IO_KICAD_SEXPR_PARSER::parseSchBezier() SCH_SHAPE* SCH_IO_KICAD_SEXPR_PARSER::parseSchBezier()
{ {
wxCHECK_MSG( CurTok() == T_bezier, nullptr, wxCHECK_MSG( CurTok() == T_bezier, nullptr,

View File

@ -45,6 +45,7 @@ class SCH_SYMBOL;
class SCH_FIELD; class SCH_FIELD;
class SCH_ITEM; class SCH_ITEM;
class SCH_SHAPE; class SCH_SHAPE;
class SCH_RULE_AREA;
class SCH_JUNCTION; class SCH_JUNCTION;
class SCH_LINE; class SCH_LINE;
class SCH_NO_CONNECT; class SCH_NO_CONNECT;
@ -221,6 +222,7 @@ private:
SCH_SHAPE* parseSchCircle(); SCH_SHAPE* parseSchCircle();
SCH_SHAPE* parseSchRectangle(); SCH_SHAPE* parseSchRectangle();
SCH_SHAPE* parseSchBezier(); SCH_SHAPE* parseSchBezier();
SCH_RULE_AREA* parseSchRuleArea();
SCH_TEXT* parseSchText(); SCH_TEXT* parseSchText();
SCH_TEXTBOX* parseSchTextBox(); SCH_TEXTBOX* parseSchTextBox();
void parseSchTextBoxContent( SCH_TEXTBOX* aTextBox ); void parseSchTextBoxContent( SCH_TEXTBOX* aTextBox );

View File

@ -26,6 +26,7 @@
#define SCH_ITEM_H #define SCH_ITEM_H
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <map> #include <map>
#include <set> #include <set>
@ -44,6 +45,7 @@ class SCHEMATIC;
class SYMBOL; class SYMBOL;
class LINE_READER; class LINE_READER;
class SCH_EDIT_FRAME; class SCH_EDIT_FRAME;
class SCH_RULE_AREA;
struct SCH_PLOT_OPTS; struct SCH_PLOT_OPTS;
namespace KIFONT namespace KIFONT
@ -628,6 +630,24 @@ public:
wxCHECK_MSG( false, /*void*/, wxT( "Plot not implemented in " ) + GetClass() ); wxCHECK_MSG( false, /*void*/, wxT( "Plot not implemented in " ) + GetClass() );
} }
/**
* Reset the cache of rule areas (called prior to schematic connectivity recomputation)
*/
void ClearRuleAreasCache() { m_rule_areas_cache.clear(); }
/**
* Adds a rule area to the item's cache
*/
void AddRuleAreaToCache( SCH_RULE_AREA* aRuleArea ) { m_rule_areas_cache.insert( aRuleArea ); }
/**
* Gets the cache of rule areas enclosing this item
*/
const std::unordered_set<SCH_RULE_AREA*>& GetRuleAreaCache() const
{
return m_rule_areas_cache;
}
/** /**
* The list of flags used by the #compare function. * The list of flags used by the #compare function.
* *
@ -721,6 +741,9 @@ protected:
bool m_connectivity_dirty; bool m_connectivity_dirty;
/// Store pointers to rule areas which this item is contained within
std::unordered_set<SCH_RULE_AREA*> m_rule_areas_cache;
private: private:
friend class LIB_SYMBOL; friend class LIB_SYMBOL;
}; };

View File

@ -1808,6 +1808,30 @@ wxString SCH_DIRECTIVE_LABEL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider
} }
void SCH_DIRECTIVE_LABEL::AddConnectedRuleArea( SCH_RULE_AREA* aRuleArea )
{
m_connected_rule_areas.insert( aRuleArea );
}
void SCH_DIRECTIVE_LABEL::ClearConnectedRuleAreas()
{
m_connected_rule_areas.clear();
}
void SCH_DIRECTIVE_LABEL::RemoveConnectedRuleArea( SCH_RULE_AREA* aRuleArea )
{
m_connected_rule_areas.erase( aRuleArea );
}
bool SCH_DIRECTIVE_LABEL::IsDangling() const
{
return m_isDangling && m_connected_rule_areas.empty();
}
SCH_GLOBALLABEL::SCH_GLOBALLABEL( const VECTOR2I& pos, const wxString& text ) : SCH_GLOBALLABEL::SCH_GLOBALLABEL( const VECTOR2I& pos, const wxString& text ) :
SCH_LABEL_BASE( pos, text, SCH_GLOBAL_LABEL_T ) SCH_LABEL_BASE( pos, text, SCH_GLOBAL_LABEL_T )
{ {

View File

@ -30,6 +30,8 @@
#include <sch_field.h> #include <sch_field.h>
#include <sch_connection.h> // for CONNECTION_TYPE #include <sch_connection.h> // for CONNECTION_TYPE
class SCH_RULE_AREA;
/* /*
* Spin style for labels of all kinds on schematics * Spin style for labels of all kinds on schematics
@ -474,9 +476,24 @@ public:
void MirrorHorizontally( int aCenter ) override; void MirrorHorizontally( int aCenter ) override;
void MirrorVertically( int aCenter ) override; void MirrorVertically( int aCenter ) override;
/// @brief Adds an entry to the connected rule area cache
void AddConnectedRuleArea( SCH_RULE_AREA* aRuleArea );
/// @brief Removes all rule areas from the cache
void ClearConnectedRuleAreas();
/// @brief Removes a specific rule area from the cache
void RemoveConnectedRuleArea( SCH_RULE_AREA* aRuleArea );
/// @brief Determines dangling state from connectivity and cached connected rule areas
virtual bool IsDangling() const override;
private: private:
int m_pinLength; int m_pinLength;
int m_symbolSize; int m_symbolSize;
/// Cache of any rule areas with borders which this label connects to
std::unordered_set<SCH_RULE_AREA*> m_connected_rule_areas;
}; };

View File

@ -79,6 +79,7 @@ std::vector<KICAD_T> SCH_PAINTER::g_ScaledSelectionTypes = {
SCH_BUS_BUS_ENTRY_T, SCH_BUS_BUS_ENTRY_T,
SCH_LINE_T, SCH_LINE_T,
SCH_SHAPE_T, SCH_SHAPE_T,
SCH_RULE_AREA_T,
SCH_BITMAP_T, SCH_BITMAP_T,
SCH_TEXT_T, SCH_TEXT_T,
SCH_GLOBAL_LABEL_T, SCH_GLOBAL_LABEL_T,
@ -194,6 +195,9 @@ void SCH_PAINTER::draw( const EDA_ITEM* aItem, int aLayer, bool aDimmed )
case SCH_SHAPE_T: case SCH_SHAPE_T:
draw( static_cast<const SCH_SHAPE*>( aItem ), aLayer, aDimmed ); draw( static_cast<const SCH_SHAPE*>( aItem ), aLayer, aDimmed );
break; break;
case SCH_RULE_AREA_T:
draw( static_cast<const SCH_SHAPE*>( aItem ), aLayer, aDimmed );
break;
case SCH_TEXT_T: case SCH_TEXT_T:
draw( static_cast<const SCH_TEXT*>( aItem ), aLayer, aDimmed ); draw( static_cast<const SCH_TEXT*>( aItem ), aLayer, aDimmed );
break; break;
@ -352,7 +356,7 @@ COLOR4D SCH_PAINTER::getRenderColor( const SCH_ITEM* aItem, int aLayer, bool aDr
else else
color = sheet->GetBorderColor(); color = sheet->GetBorderColor();
} }
else if( aItem->Type() == SCH_SHAPE_T ) else if( aItem->Type() == SCH_SHAPE_T || aItem->Type() == SCH_RULE_AREA_T )
{ {
const SCH_SHAPE* shape = static_cast<const SCH_SHAPE*>( aItem ); const SCH_SHAPE* shape = static_cast<const SCH_SHAPE*>( aItem );
@ -373,7 +377,17 @@ COLOR4D SCH_PAINTER::getRenderColor( const SCH_ITEM* aItem, int aLayer, bool aDr
// A filled shape means filled; if they didn't specify a fill colour then use the // A filled shape means filled; if they didn't specify a fill colour then use the
// border colour. // border colour.
if( color == COLOR4D::UNSPECIFIED ) if( color == COLOR4D::UNSPECIFIED )
color = m_schSettings.GetLayerColor( isSymbolChild ? LAYER_DEVICE : LAYER_NOTES ); {
if( aItem->Type() == SCH_RULE_AREA_T )
{
color = m_schSettings.GetLayerColor( LAYER_RULE_AREAS );
}
else
{
color = m_schSettings.GetLayerColor( isSymbolChild ? LAYER_DEVICE
: LAYER_NOTES );
}
}
} }
else if( aItem->IsType( { SCH_LABEL_LOCATE_ANY_T } ) ) else if( aItem->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
{ {
@ -1566,11 +1580,20 @@ void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer, bool aDimmed )
case SHAPE_T::POLY: case SHAPE_T::POLY:
{ {
const SHAPE_LINE_CHAIN poly = shape->GetPolyShape().Outline( 0 ); const std::vector<SHAPE*> polySegments = shape->MakeEffectiveShapes( true );
std::deque<VECTOR2D> mappedPts; std::deque<VECTOR2D> mappedPts;
for( const VECTOR2I& pt : poly.CPoints() ) for( SHAPE* polySegment : polySegments )
mappedPts.push_back( MAP_COORDS( pt ) ); {
mappedPts.push_back( MAP_COORDS(
static_cast<SHAPE_SEGMENT*>( polySegment )->GetSeg().A ) );
}
mappedPts.push_back( MAP_COORDS(
static_cast<SHAPE_SEGMENT*>( polySegments.back() )->GetSeg().B ) );
for( SHAPE* polySegment : polySegments )
delete polySegment;
m_gal->DrawPolygon( mappedPts ); m_gal->DrawPolygon( mappedPts );
break; break;
@ -1629,7 +1652,8 @@ void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer, bool aDimmed )
drawShape( aShape ); drawShape( aShape );
} }
} }
else if( aLayer == LAYER_DEVICE || aLayer == LAYER_NOTES || aLayer == LAYER_PRIVATE_NOTES ) else if( aLayer == LAYER_DEVICE || aLayer == LAYER_NOTES || aLayer == LAYER_PRIVATE_NOTES
|| aLayer == LAYER_RULE_AREAS )
{ {
float lineWidth = getLineWidth( aShape, drawingShadows ); float lineWidth = getLineWidth( aShape, drawingShadows );

View File

@ -27,6 +27,7 @@
#ifndef SCH_PLOTTER_H #ifndef SCH_PLOTTER_H
#define SCH_PLOTTER_H #define SCH_PLOTTER_H
#include <wx/filename.h>
#include <wx/string.h> #include <wx/string.h>
#include <wx/gdicmn.h> #include <wx/gdicmn.h>
#include <page_info.h> #include <page_info.h>

442
eeschema/sch_rule_area.cpp Normal file
View File

@ -0,0 +1,442 @@
/*
* 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 <algorithm>
#include <iterator>
#include <map>
#include <vector>
#include <eda_draw_frame.h>
#include <erc_item.h>
#include <erc_settings.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_simple.h>
#include <sch_line.h>
#include <sch_marker.h>
#include <sch_rtree.h>
#include <sch_rule_area.h>
#include <sch_screen.h>
#include <sch_sheet_path.h>
wxString SCH_RULE_AREA::GetClass() const
{
return wxT( "SCH_RULE_AREA" );
}
wxString SCH_RULE_AREA::GetFriendlyName() const
{
return _( "Rule Area" );
}
EDA_ITEM* SCH_RULE_AREA::Clone() const
{
return new SCH_RULE_AREA( *this );
}
void SCH_RULE_AREA::ViewGetLayers( int aLayers[], int& aCount ) const
{
aCount = 3;
aLayers[0] = LAYER_RULE_AREAS;
aLayers[1] = LAYER_NOTES_BACKGROUND;
aLayers[2] = LAYER_SELECTION_SHADOWS;
}
std::vector<SHAPE*> SCH_RULE_AREA::MakeEffectiveShapes( bool aEdgeOnly ) const
{
std::vector<SHAPE*> effectiveShapes;
int width = GetEffectiveWidth();
switch( m_shape )
{
case SHAPE_T::POLY:
{
if( GetPolyShape().OutlineCount() == 0 ) // malformed/empty polygon
break;
for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii )
{
const SHAPE_LINE_CHAIN& l = GetPolyShape().COutline( ii );
if( IsFilled() && !aEdgeOnly )
effectiveShapes.emplace_back( new SHAPE_SIMPLE( l ) );
if( width > 0 || !IsFilled() || aEdgeOnly )
{
int segCount = l.SegmentCount();
for( int jj = 0; jj < segCount; jj++ )
effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.CSegment( jj ), width ) );
}
}
}
break;
default:
return SCH_SHAPE::MakeEffectiveShapes( aEdgeOnly );
break;
}
return effectiveShapes;
}
void SCH_RULE_AREA::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
{
if( IsPrivate() )
return;
SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
int pen_size = GetEffectivePenWidth( renderSettings );
if( GetShape() != SHAPE_T::POLY )
SCH_SHAPE::Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed );
static std::vector<VECTOR2I> ptList;
ptList.clear();
const std::vector<VECTOR2I>& polyPoints = m_poly.Outline( 0 ).CPoints();
for( const VECTOR2I& pt : polyPoints )
{
ptList.push_back( pt );
}
ptList.push_back( polyPoints[0] );
COLOR4D color = GetStroke().GetColor();
COLOR4D bg = renderSettings->GetBackgroundColor();
LINE_STYLE lineStyle = GetStroke().GetLineStyle();
FILL_T fill = m_fill;
if( aBackground )
{
if( !aPlotter->GetColorMode() )
return;
switch( m_fill )
{
case FILL_T::FILLED_SHAPE:
return;
case FILL_T::FILLED_WITH_COLOR:
color = GetFillColor();
break;
case FILL_T::FILLED_WITH_BG_BODYCOLOR:
color = renderSettings->GetLayerColor( LAYER_DEVICE_BACKGROUND );
break;
default:
return;
}
pen_size = 0;
lineStyle = LINE_STYLE::SOLID;
}
else /* if( aForeground ) */
{
if( !aPlotter->GetColorMode() || color == COLOR4D::UNSPECIFIED )
color = renderSettings->GetLayerColor( m_layer );
if( lineStyle == LINE_STYLE::DEFAULT )
lineStyle = LINE_STYLE::SOLID;
if( m_fill == FILL_T::FILLED_SHAPE )
fill = m_fill;
else
fill = FILL_T::NO_FILL;
pen_size = GetEffectivePenWidth( renderSettings );
}
if( bg == COLOR4D::UNSPECIFIED || !aPlotter->GetColorMode() )
bg = COLOR4D::WHITE;
if( aDimmed )
{
color.Desaturate();
color = color.Mix( bg, 0.5f );
}
aPlotter->SetColor( color );
aPlotter->SetCurrentLineWidth( pen_size );
aPlotter->SetDash( pen_size, lineStyle );
aPlotter->PlotPoly( ptList, fill, pen_size );
aPlotter->SetDash( pen_size, LINE_STYLE::SOLID );
}
wxString SCH_RULE_AREA::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
{
return _( "Schematic rule area" );
}
void SCH_RULE_AREA::ResetCaches( KIGFX::SCH_VIEW* view )
{
// Save the current state
m_prev_items = m_items;
m_prev_directives = m_directives;
// Reset the rule area
clearContainedItems();
clearDirectives( view );
}
void SCH_RULE_AREA::RefreshContainedItemsAndDirectives(
SCH_SCREEN* screen, KIGFX::SCH_VIEW* view,
std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>>& forceUpdateRuleAreas )
{
EE_RTREE& items = screen->Items();
const BOX2I boundingBox = GetBoundingBox();
// Get any SCH_DIRECTIVE_LABELs which are attached to the rule area border
std::unordered_set<SCH_DIRECTIVE_LABEL*> attachedDirectives;
EE_RTREE::EE_TYPE candidateDirectives = items.Overlapping( SCH_DIRECTIVE_LABEL_T, boundingBox );
for( SCH_ITEM* candidateDirective : candidateDirectives )
{
SCH_DIRECTIVE_LABEL* label = static_cast<SCH_DIRECTIVE_LABEL*>( candidateDirective );
const std::vector<VECTOR2I> labelConnectionPoints = label->GetConnectionPoints();
assert( labelConnectionPoints.size() == 1 );
if( GetPolyShape().CollideEdge( labelConnectionPoints[0], nullptr, 5 ) )
{
addDirective( label, view );
}
}
// If directives have changed, we need to force an update of the contained items connectivity
if( m_directives != m_prev_directives )
forceUpdateRuleAreas.push_back( { this, screen } );
// Next find any connectable items which lie within the rule area
EE_RTREE::EE_TYPE ruleAreaItems = items.Overlapping( boundingBox );
for( SCH_ITEM* areaItem : ruleAreaItems )
{
if( areaItem->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } ) )
{
SCH_LINE* lineItem = static_cast<SCH_LINE*>( areaItem );
SHAPE_SEGMENT lineSeg( lineItem->GetStartPoint(), lineItem->GetEndPoint(),
lineItem->GetLineWidth() );
if( GetPolyShape().Collide( &lineSeg ) )
{
addContainedItem( areaItem );
}
}
else if( areaItem->IsType(
{ SCH_PIN_T, SCH_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T } ) )
{
std::vector<VECTOR2I> connectionPoints = areaItem->GetConnectionPoints();
assert( connectionPoints.size() == 1 );
if( GetPolyShape().Collide( connectionPoints[0] ) )
{
addContainedItem( areaItem );
}
}
}
}
std::unordered_set<SCH_ITEM*> SCH_RULE_AREA::GetPastAndPresentContainedItems() const
{
std::unordered_set<SCH_ITEM*> items = m_items;
for( SCH_ITEM* item : m_prev_items )
items.insert( item );
return items;
}
std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>>
SCH_RULE_AREA::UpdateRuleAreasInScreens( std::unordered_set<SCH_SCREEN*>& screens,
KIGFX::SCH_VIEW* view )
{
std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>> forceUpdateRuleAreas;
for( SCH_SCREEN* screen : screens )
{
// First reset all item caches - must be done first to ensure two rule areas
// on the same item don't overwrite each other's caches
for( SCH_ITEM* ruleAreaAsItem : screen->Items().OfType( SCH_RULE_AREA_T ) )
{
SCH_RULE_AREA* ruleArea = static_cast<SCH_RULE_AREA*>( ruleAreaAsItem );
ruleArea->ResetCaches( view );
}
// Secondly refresh the contained items
for( SCH_ITEM* ruleAreaAsItem : screen->Items().OfType( SCH_RULE_AREA_T ) )
{
SCH_RULE_AREA* ruleArea = static_cast<SCH_RULE_AREA*>( ruleAreaAsItem );
ruleArea->RefreshContainedItemsAndDirectives( screen, view, forceUpdateRuleAreas );
}
}
return forceUpdateRuleAreas;
}
const std::unordered_set<SCH_ITEM*>& SCH_RULE_AREA::GetContainedItems() const
{
return m_items;
}
const std::unordered_set<SCH_DIRECTIVE_LABEL*> SCH_RULE_AREA::GetDirectives() const
{
return m_directives;
}
const std::vector<std::pair<wxString, SCH_ITEM*>> SCH_RULE_AREA::GetResolvedNetclasses() const
{
std::vector<std::pair<wxString, SCH_ITEM*>> resolvedNetclasses;
for( SCH_DIRECTIVE_LABEL* directive : m_directives )
{
directive->RunOnChildren(
[&]( SCH_ITEM* aChild )
{
if( aChild->Type() == SCH_FIELD_T )
{
SCH_FIELD* field = static_cast<SCH_FIELD*>( aChild );
if( field->GetCanonicalName() == wxT( "Netclass" ) )
{
wxString netclass = field->GetText();
if( netclass != wxEmptyString )
resolvedNetclasses.push_back( { netclass, directive } );
}
}
return true;
} );
}
return resolvedNetclasses;
}
void SCH_RULE_AREA::ResetDirectivesAndItems( KIGFX::SCH_VIEW* view )
{
for( SCH_DIRECTIVE_LABEL* label : m_directives )
{
label->ClearConnectedRuleAreas();
view->Update( label, KIGFX::REPAINT );
}
for( SCH_ITEM* item : m_items )
item->ClearRuleAreasCache();
}
void SCH_RULE_AREA::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
{
aList.emplace_back( _( "Rule Area" ), wxEmptyString );
wxString msg;
msg.Printf( wxS( "%d" ), GetPolyShape().Outline( 0 ).PointCount() );
aList.emplace_back( _( "Points" ), msg );
m_stroke.GetMsgPanelInfo( aFrame, aList );
const std::vector<std::pair<wxString, SCH_ITEM*>> netclasses =
SCH_RULE_AREA::GetResolvedNetclasses();
wxString resolvedNetclass = _( "<None>" );
if( netclasses.size() > 0 )
resolvedNetclass = netclasses[0].first;
aList.emplace_back( _( "Resolved netclass" ), resolvedNetclass );
}
void SCH_RULE_AREA::addDirective( SCH_DIRECTIVE_LABEL* label, KIGFX::SCH_VIEW* view )
{
label->AddConnectedRuleArea( this );
m_directives.insert( label );
if( view )
view->Update( label, KIGFX::REPAINT );
}
void SCH_RULE_AREA::clearDirectives( KIGFX::SCH_VIEW* view )
{
for( SCH_DIRECTIVE_LABEL* label : m_directives )
{
label->ClearConnectedRuleAreas();
if( view )
view->Update( label, KIGFX::REPAINT );
}
m_directives.clear();
}
void SCH_RULE_AREA::addContainedItem( SCH_ITEM* item )
{
item->AddRuleAreaToCache( this );
m_items.insert( item );
}
void SCH_RULE_AREA::clearContainedItems()
{
for( SCH_ITEM* item : m_items )
item->ClearRuleAreasCache();
m_items.clear();
}
static struct SCH_RULE_AREA_DESC
{
SCH_RULE_AREA_DESC()
{
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
REGISTER_TYPE( SCH_RULE_AREA );
propMgr.AddTypeCast( new TYPE_CAST<SCH_RULE_AREA, SCH_SHAPE> );
propMgr.AddTypeCast( new TYPE_CAST<SCH_RULE_AREA, SCH_ITEM> );
propMgr.AddTypeCast( new TYPE_CAST<SCH_RULE_AREA, EDA_SHAPE> );
propMgr.InheritsAfter( TYPE_HASH( SCH_RULE_AREA ), TYPE_HASH( SCH_SHAPE ) );
propMgr.InheritsAfter( TYPE_HASH( SCH_RULE_AREA ), TYPE_HASH( SCH_ITEM ) );
propMgr.InheritsAfter( TYPE_HASH( SCH_RULE_AREA ), TYPE_HASH( EDA_SHAPE ) );
}
} _SCH_RULE_AREA_DESC;

125
eeschema/sch_rule_area.h Normal file
View File

@ -0,0 +1,125 @@
/*
* 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
*/
#ifndef SCH_RULE_AREA_H
#define SCH_RULE_AREA_H
#include <unordered_set>
#include <utility>
#include <plotters/plotter.h>
#include <sch_plotter.h>
#include <sch_screen.h>
#include <sch_shape.h>
#include <sch_label.h>
#include <sch_sheet_path.h>
#include <sch_view.h>
class SCHEMATIC;
class SCH_RULE_AREA : public SCH_SHAPE
{
public:
SCH_RULE_AREA() :
SCH_SHAPE( SHAPE_T::POLY, LAYER_RULE_AREAS, 0 /* line width */, FILL_T::NO_FILL,
SCH_RULE_AREA_T )
{
SetLayer( LAYER_RULE_AREAS );
}
virtual ~SCH_RULE_AREA() {}
wxString GetClass() const override;
wxString GetFriendlyName() const override;
EDA_ITEM* Clone() const override;
void ViewGetLayers( int aLayers[], int& aCount ) const override;
virtual std::vector<SHAPE*> MakeEffectiveShapes( bool aEdgeOnly = false ) const override;
virtual void Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed ) override;
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const override;
/// @brief Resets all item and directive caches, saving the current state first
void ResetCaches( KIGFX::SCH_VIEW* view );
/// @brief Refreshes the list of items which this rule area affects
void RefreshContainedItemsAndDirectives(
SCH_SCREEN* screen, KIGFX::SCH_VIEW* view,
std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>>& forceUpdateRuleAreas );
/// @brief Fetches all items which were, or are, within the rule area
std::unordered_set<SCH_ITEM*> GetPastAndPresentContainedItems() const;
/// @brief Updates all rule area connectvity / caches in the given sheet paths
/// @returns A map of all updated rule areas and their owning screen
static std::vector<std::pair<SCH_RULE_AREA*, SCH_SCREEN*>>
UpdateRuleAreasInScreens( std::unordered_set<SCH_SCREEN*>& screens, KIGFX::SCH_VIEW* view );
/// @brief Returns a set of all items contained within the rule area
const std::unordered_set<SCH_ITEM*>& GetContainedItems() const;
/// @brief Returns the set of all directive labels attached to the rule area border
const std::unordered_set<SCH_DIRECTIVE_LABEL*> GetDirectives() const;
/// @brief Resolves the netclass of this rule area from connected directive labels
/// @returns The resolved netclass (if any), and the SCH_ITEM providing the declaration
const std::vector<std::pair<wxString, SCH_ITEM*>> GetResolvedNetclasses() const;
/// @brief Clears and resets items and directives attached to this rule area
void ResetDirectivesAndItems( KIGFX::SCH_VIEW* view );
/// @brief Gets the message panel info for the rule area
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
protected:
/// @brief Adds a directive label which applies to items within ths rule area
void addDirective( SCH_DIRECTIVE_LABEL* label, KIGFX::SCH_VIEW* view );
/// @brief Clears the list of directives
void clearDirectives( KIGFX::SCH_VIEW* view );
/// @briefs Adds an item to the list of items which this rule area affects
void addContainedItem( SCH_ITEM* item );
/// @brief Clears the list of items which this rule area affects
void clearContainedItems();
/// All SCH_ITEMs currently contained or intersecting the rule area
std::unordered_set<SCH_ITEM*> m_items;
/// All SCH_DIRECTIVE_LABELs attached to the rule area border
std::unordered_set<SCH_DIRECTIVE_LABEL*> m_directives;
/// All SCH_ITEMs contained or intersecting the rule area in the previous update
std::unordered_set<SCH_ITEM*> m_prev_items;
/// All SCH_DIRECTIVE_LABELs attached to the rule area border in the previous update
std::unordered_set<SCH_DIRECTIVE_LABEL*> m_prev_directives;
};
#endif

View File

@ -49,7 +49,7 @@ static const int SCH_LAYER_ORDER[] =
LAYER_OP_VOLTAGES, LAYER_OP_CURRENTS, LAYER_OP_VOLTAGES, LAYER_OP_CURRENTS,
LAYER_REFERENCEPART, LAYER_VALUEPART, LAYER_FIELDS, LAYER_REFERENCEPART, LAYER_VALUEPART, LAYER_FIELDS,
LAYER_PINNUM, LAYER_PINNAM, LAYER_PINNUM, LAYER_PINNAM,
LAYER_INTERSHEET_REFS, LAYER_NETCLASS_REFS, LAYER_INTERSHEET_REFS, LAYER_NETCLASS_REFS, LAYER_RULE_AREAS,
LAYER_BUS_JUNCTION, LAYER_JUNCTION, LAYER_NOCONNECT, LAYER_BUS_JUNCTION, LAYER_JUNCTION, LAYER_NOCONNECT,
LAYER_HIERLABEL, LAYER_GLOBLABEL, LAYER_LOCLABEL, LAYER_HIERLABEL, LAYER_GLOBLABEL, LAYER_LOCLABEL,
LAYER_SHEETFILENAME, LAYER_SHEETNAME, LAYER_SHEETLABEL, LAYER_SHEETFIELDS, LAYER_SHEETFILENAME, LAYER_SHEETNAME, LAYER_SHEETLABEL, LAYER_SHEETFIELDS,

View File

@ -128,6 +128,7 @@ right
round round
rows rows
row_heights row_heights
rule_area
scale scale
separators separators
shape shape

View File

@ -294,7 +294,9 @@ void SCH_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList )
// Set connectable object connectivity status. // Set connectable object connectivity status.
auto updateConnectivityFlag = [&, this]() auto updateConnectivityFlag = [&, this]()
{ {
if( schItem && schItem->IsConnectable() ) if( schItem )
{
if( schItem->IsConnectable() )
{ {
schItem->SetConnectivityDirty(); schItem->SetConnectivityDirty();
@ -328,6 +330,11 @@ void SCH_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList )
if( schItem->Type() == SCH_SHEET_T ) if( schItem->Type() == SCH_SHEET_T )
connectivityCleanUp = GLOBAL_CLEANUP; connectivityCleanUp = GLOBAL_CLEANUP;
} }
else if( schItem->Type() == SCH_RULE_AREA_T )
{
dirtyConnectivity = true;
}
}
}; };
if( status == UNDO_REDO::NEWITEM ) if( status == UNDO_REDO::NEWITEM )

View File

@ -175,6 +175,7 @@ void SCH_EDIT_FRAME::ReCreateVToolbar()
m_drawToolBar->Add( EE_ACTIONS::placeJunction, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::placeJunction, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::placeLabel, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::placeLabel, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::placeClassLabel, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::placeClassLabel, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::drawRuleArea, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::placeGlobalLabel, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::placeGlobalLabel, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::placeHierLabel, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::placeHierLabel, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::drawSheet, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::drawSheet, ACTION_TOOLBAR::TOGGLE );

View File

@ -607,6 +607,29 @@ TOOL_ACTION EE_ACTIONS::placeImage( TOOL_ACTION_ARGS()
.Flags( AF_ACTIVATE ) .Flags( AF_ACTIVATE )
.Parameter<SCH_BITMAP*>( nullptr ) ); .Parameter<SCH_BITMAP*>( nullptr ) );
TOOL_ACTION EE_ACTIONS::drawRuleArea( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveDrawing.drawRuleArea" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Add Rule Area" ) )
.Tooltip( _( "Draw rule area" ) )
.Icon( BITMAPS::add_keepout_area )
.Flags( AF_ACTIVATE )
.Parameter( SHAPE_T::RECTANGLE ) );
TOOL_ACTION EE_ACTIONS::deleteLastPoint( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveDrawing.deleteLastPoint" )
.Scope( AS_CONTEXT )
.FriendlyName( _( "Delete Last Point" ) )
.Tooltip( _( "Delete the last point added to the current item" ) )
.Icon( BITMAPS::undo ) );
TOOL_ACTION EE_ACTIONS::closeOutline( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveDrawing.closeOutline" )
.Scope( AS_CONTEXT )
.FriendlyName( _( "Close Outline" ) )
.Tooltip( _( "Close the in progress outline" ) )
.Icon( BITMAPS::checked_ok ) );
// SCH_EDIT_TOOL // SCH_EDIT_TOOL
// //

View File

@ -104,6 +104,9 @@ public:
static TOOL_ACTION placeImage; static TOOL_ACTION placeImage;
static TOOL_ACTION undoLastSegment; static TOOL_ACTION undoLastSegment;
static TOOL_ACTION switchSegmentPosture; static TOOL_ACTION switchSegmentPosture;
static TOOL_ACTION drawRuleArea;
static TOOL_ACTION deleteLastPoint;
static TOOL_ACTION closeOutline;
// Symbol Tools // Symbol Tools
static TOOL_ACTION placeSymbolPin; static TOOL_ACTION placeSymbolPin;

View File

@ -373,6 +373,7 @@ GRID_HELPER_GRIDS EE_GRID_HELPER::GetItemGrid( const EDA_ITEM* aItem ) const
case SCH_HIER_LABEL_T: case SCH_HIER_LABEL_T:
case SCH_LABEL_T: case SCH_LABEL_T:
case SCH_DIRECTIVE_LABEL_T: case SCH_DIRECTIVE_LABEL_T:
case SCH_RULE_AREA_T:
return GRID_CONNECTABLE; return GRID_CONNECTABLE;
case SCH_FIELD_T: case SCH_FIELD_T:

View File

@ -164,6 +164,16 @@ public:
break; break;
} }
case SCH_RULE_AREA_T:
{
SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aItem );
for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
points->AddPoint( pt );
break;
}
case SCH_TEXTBOX_T: case SCH_TEXTBOX_T:
{ {
SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( aItem ); SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( aItem );
@ -373,6 +383,7 @@ int EE_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
const EE_SELECTION& selection = m_selectionTool->GetSelection(); const EE_SELECTION& selection = m_selectionTool->GetSelection();
if( selection.Size() != 1 || !selection.Front()->IsType( { SCH_SHAPE_T, if( selection.Size() != 1 || !selection.Front()->IsType( { SCH_SHAPE_T,
SCH_RULE_AREA_T,
SCH_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_TABLECELL_T, SCH_TABLECELL_T,
SCH_SHEET_T, SCH_SHEET_T,
@ -632,6 +643,7 @@ void EE_POINT_EDITOR::updateParentItem( bool aSnapToGrid ) const
switch( item->Type() ) switch( item->Type() )
{ {
case SCH_RULE_AREA_T:
case SCH_SHAPE_T: case SCH_SHAPE_T:
{ {
SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item ); SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
@ -1149,8 +1161,16 @@ void EE_POINT_EDITOR::setEditedPoint( EDIT_POINT* aPoint )
bool EE_POINT_EDITOR::removeCornerCondition( const SELECTION& ) bool EE_POINT_EDITOR::removeCornerCondition( const SELECTION& )
{ {
if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != SCH_SHAPE_T ) bool isRuleArea = false;
if( m_editPoints )
isRuleArea = m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T;
if( !m_editPoints || !m_editedPoint
|| !( m_editPoints->GetParent()->Type() == SCH_SHAPE_T || isRuleArea ) )
{
return false; return false;
}
SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() ); SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
bool invertY = shape->GetLayer() == LAYER_DEVICE; bool invertY = shape->GetLayer() == LAYER_DEVICE;
@ -1165,7 +1185,10 @@ bool EE_POINT_EDITOR::removeCornerCondition( const SELECTION& )
for( const VECTOR2I& pt : poly.CPoints() ) for( const VECTOR2I& pt : poly.CPoints() )
{ {
if( pt == mapCoords( m_editedPoint->GetPosition(), invertY ) ) VECTOR2I adjustedPos = isRuleArea ? m_editedPoint->GetPosition()
: mapCoords( m_editedPoint->GetPosition(), invertY );
if( pt == adjustedPos )
return true; return true;
} }
@ -1175,8 +1198,12 @@ bool EE_POINT_EDITOR::removeCornerCondition( const SELECTION& )
bool EE_POINT_EDITOR::addCornerCondition( const SELECTION& ) bool EE_POINT_EDITOR::addCornerCondition( const SELECTION& )
{ {
if( !m_editPoints || m_editPoints->GetParent()->Type() != SCH_SHAPE_T ) if( !m_editPoints
|| !( m_editPoints->GetParent()->Type() == SCH_SHAPE_T
|| m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T ) )
{
return false; return false;
}
SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() ); SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
@ -1192,7 +1219,9 @@ bool EE_POINT_EDITOR::addCornerCondition( const SELECTION& )
int EE_POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent ) int EE_POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent )
{ {
if( !m_editPoints || m_editPoints->GetParent()->Type() != SCH_SHAPE_T ) if( !m_editPoints
|| !( m_editPoints->GetParent()->Type() == SCH_SHAPE_T
|| m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T ) )
return 0; return 0;
SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() ); SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
@ -1206,8 +1235,12 @@ int EE_POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent )
VECTOR2I pos = mapCoords( cursor, invertY ); VECTOR2I pos = mapCoords( cursor, invertY );
int currentMinDistance = INT_MAX; int currentMinDistance = INT_MAX;
int closestLineStart = 0; int closestLineStart = 0;
unsigned numPoints = poly.GetPointCount();
for( unsigned i = 0; i < poly.GetPointCount() - 1; ++i ) if( !shape->IsClosed() )
numPoints -= 1;
for( unsigned i = 0; i < numPoints; ++i )
{ {
int distance = (int) DistanceLinePoint( poly.CPoint( i ), int distance = (int) DistanceLinePoint( poly.CPoint( i ),
poly.CPoint( i + 1 ), pos ); poly.CPoint( i + 1 ), pos );
@ -1231,8 +1264,12 @@ int EE_POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent )
int EE_POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent ) int EE_POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent )
{ {
if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != SCH_SHAPE_T ) if( !m_editPoints || !m_editedPoint
|| !( m_editPoints->GetParent()->Type() == SCH_SHAPE_T
|| m_editPoints->GetParent()->Type() == SCH_RULE_AREA_T ) )
{
return 0; return 0;
}
SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() ); SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( m_editPoints->GetParent() );
SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 ); SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );

View File

@ -0,0 +1,175 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017-2023 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 <core/spinlock.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_line_chain.h>
#include <sch_commit.h>
#include <sch_edit_frame.h>
#include <sch_rule_area.h>
#include <tool/tool_manager.h>
#include <tools/ee_actions.h>
#include <tools/rule_area_create_helper.h>
RULE_AREA_CREATE_HELPER::RULE_AREA_CREATE_HELPER( KIGFX::VIEW& aView, SCH_EDIT_FRAME* aFrame,
TOOL_MANAGER* aMgr ) :
m_parentView( aView ),
m_frame( aFrame ), m_toolManager( aMgr )
{
m_parentView.Add( &m_previewItem );
}
RULE_AREA_CREATE_HELPER::~RULE_AREA_CREATE_HELPER()
{
// remove the preview from the view
m_parentView.SetVisible( &m_previewItem, false );
m_parentView.Remove( &m_previewItem );
}
std::unique_ptr<SCH_RULE_AREA> RULE_AREA_CREATE_HELPER::createNewRuleArea()
{
std::unique_ptr<SCH_RULE_AREA> ruleArea = std::make_unique<SCH_RULE_AREA>();
ruleArea->SetLineStyle( LINE_STYLE::DASH );
ruleArea->SetLineColor( COLOR4D::UNSPECIFIED );
return ruleArea;
}
void RULE_AREA_CREATE_HELPER::commitRuleArea( std::unique_ptr<SCH_RULE_AREA> aRuleArea )
{
SCH_COMMIT commit( m_toolManager );
SCH_RULE_AREA* ruleArea = aRuleArea.release();
commit.Add( ruleArea, m_frame->GetScreen() );
commit.Push( _( "Draw Rule Area" ) );
m_toolManager->RunAction<EDA_ITEM*>( EE_ACTIONS::addItemToSel, ruleArea );
m_parentView.ClearPreview();
}
bool RULE_AREA_CREATE_HELPER::OnFirstPoint( POLYGON_GEOM_MANAGER& aMgr )
{
m_rule_area = createNewRuleArea();
if( m_rule_area )
{
m_toolManager->RunAction( EE_ACTIONS::clearSelection );
SCH_RENDER_SETTINGS renderSettings;
COLOR_SETTINGS* colorSettings = m_frame->GetColorSettings();
renderSettings.LoadColors( colorSettings );
COLOR4D color = renderSettings.GetLayerColor( LAYER_RULE_AREAS );
m_previewItem.SetLineColor( color );
m_previewItem.SetLeaderColor( color );
m_previewItem.SetFillColor( color.WithAlpha( 0.2 ) );
m_parentView.SetVisible( &m_previewItem, true );
aMgr.SetLeaderMode( POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 );
}
return m_rule_area != nullptr;
}
void RULE_AREA_CREATE_HELPER::OnGeometryChange( const POLYGON_GEOM_MANAGER& aMgr )
{
// Handle a cancel-interactive
if( m_rule_area && !aMgr.IsPolygonInProgress() )
{
m_rule_area = nullptr;
m_parentView.SetVisible( &m_previewItem, false );
return;
}
// send the points to the preview item
m_previewItem.SetPoints( aMgr.GetLockedInPoints(), aMgr.GetLeaderLinePoints(),
aMgr.GetLoopLinePoints() );
m_parentView.Update( &m_previewItem, KIGFX::GEOMETRY );
}
void RULE_AREA_CREATE_HELPER::OnComplete( const POLYGON_GEOM_MANAGER& aMgr )
{
auto& finalPoints = aMgr.GetLockedInPoints();
if( finalPoints.PointCount() < 3 )
{
// Just scrap the rule area in progress
m_rule_area = nullptr;
}
else
{
SHAPE_POLY_SET ruleShape;
ruleShape.NewOutline();
auto& outline = ruleShape.Outline( 0 );
for( int i = 0; i < finalPoints.PointCount(); ++i )
outline.Append( finalPoints.CPoint( i ) );
// In DEG45 mode, we may have intermediate points in the leader that should be included
// as they are shown in the preview. These typically maintain the 45 constraint
if( aMgr.GetLeaderMode() == POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 )
{
const SHAPE_LINE_CHAIN leaderPts = aMgr.GetLeaderLinePoints();
for( int i = 1; i < leaderPts.PointCount(); i++ )
outline.Append( leaderPts.CPoint( i ) );
const SHAPE_LINE_CHAIN loopPts = aMgr.GetLoopLinePoints();
for( int i = 1; i < loopPts.PointCount() - 1; i++ )
outline.Append( loopPts.CPoint( i ) );
}
outline.SetClosed( true );
outline.Simplify( true );
// Remove the start point if it lies on the line between neighbouring points.
// Simplify doesn't handle that currently.
if( outline.PointCount() >= 3 )
{
SEG seg( outline.CPoint( -1 ), outline.CPoint( 1 ) );
if( seg.LineDistance( outline.CPoint( 0 ) ) <= 1 )
outline.Remove( 0 );
}
m_rule_area->SetPolyShape( ruleShape );
// hand the rule area over to the committer
commitRuleArea( std::move( m_rule_area ) );
m_rule_area = nullptr;
}
m_parentView.SetVisible( &m_previewItem, false );
}

View File

@ -0,0 +1,93 @@
/*
* 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
*/
#ifndef EESCHEMA_TOOLS_RULE_CREATE_HELPER__H_
#define EESCHEMA_TOOLS_RULE_CREATE_HELPER__H_
#include <preview_items/polygon_geom_manager.h>
#include <preview_items/polygon_item.h>
#include "sch_rule_area.h"
#include <view/view.h>
namespace KIGFX
{
class VIEW;
}
class TOOL_MANAGER;
/**
* An adjunct helper to the DRAWING_TOOL interactive tool, which handles incoming geometry
* changes from a #POLYGON_GEOM_MANAGER and translates that into a SCH_RULE_AREA based on given
* parameters.
*/
class RULE_AREA_CREATE_HELPER : public POLYGON_GEOM_MANAGER::CLIENT
{
public:
RULE_AREA_CREATE_HELPER( KIGFX::VIEW& aView, SCH_EDIT_FRAME* aFrame, TOOL_MANAGER* aMgr );
virtual ~RULE_AREA_CREATE_HELPER();
SCH_RULE_AREA* GetRuleArea() const { return m_rule_area.get(); }
/*
* Interface for receiving #POLYGON_GEOM_MANAGER update
*/
void OnGeometryChange( const POLYGON_GEOM_MANAGER& aMgr ) override;
bool OnFirstPoint( POLYGON_GEOM_MANAGER& aMgr ) override;
void OnComplete( const POLYGON_GEOM_MANAGER& aMgr ) override;
/**
* Create a new SCH_RULE_AREA
*
* @return the new rule area, can be null if the user aborted
*/
std::unique_ptr<SCH_RULE_AREA> createNewRuleArea();
/**
* Commit the current rule area in progress to the schematic.
*
* @param aRuleArea is the drawn rule area outline to commit.
*/
void commitRuleArea( std::unique_ptr<SCH_RULE_AREA> aRuleArea );
private:
///< The preview item to display
KIGFX::PREVIEW::POLYGON_ITEM m_previewItem;
///< view that show the preview item
KIGFX::VIEW& m_parentView;
///< The active schematic edit frame
SCH_EDIT_FRAME* m_frame;
///< The rule area in progress
std::unique_ptr<SCH_RULE_AREA> m_rule_area;
///< The TOOL_MANAGER running the tool
TOOL_MANAGER* m_toolManager;
};
#endif // EESCHEMA_TOOLS_RULE_CREATE_HELPER__H_

View File

@ -32,6 +32,7 @@
#include <tools/sch_line_wire_bus_tool.h> #include <tools/sch_line_wire_bus_tool.h>
#include <tools/ee_selection_tool.h> #include <tools/ee_selection_tool.h>
#include <tools/ee_grid_helper.h> #include <tools/ee_grid_helper.h>
#include <tools/rule_area_create_helper.h>
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
#include <ee_actions.h> #include <ee_actions.h>
#include <sch_edit_frame.h> #include <sch_edit_frame.h>
@ -45,6 +46,7 @@
#include <sch_line.h> #include <sch_line.h>
#include <sch_junction.h> #include <sch_junction.h>
#include <sch_bus_entry.h> #include <sch_bus_entry.h>
#include <sch_rule_area.h>
#include <sch_text.h> #include <sch_text.h>
#include <sch_textbox.h> #include <sch_textbox.h>
#include <sch_table.h> #include <sch_table.h>
@ -55,6 +57,7 @@
#include <sch_bitmap.h> #include <sch_bitmap.h>
#include <schematic.h> #include <schematic.h>
#include <sch_commit.h> #include <sch_commit.h>
#include <scoped_set_reset.h>
#include <symbol_library.h> #include <symbol_library.h>
#include <eeschema_settings.h> #include <eeschema_settings.h>
#include <dialogs/dialog_label_properties.h> #include <dialogs/dialog_label_properties.h>
@ -90,6 +93,7 @@ SCH_DRAWING_TOOLS::SCH_DRAWING_TOOLS() :
m_lastTextboxStroke( 0, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ), m_lastTextboxStroke( 0, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
m_mruPath( wxEmptyString ), m_mruPath( wxEmptyString ),
m_lastAutoLabelRotateOnPlacement( false ), m_lastAutoLabelRotateOnPlacement( false ),
m_drawingRuleArea( false ),
m_inDrawingTool( false ) m_inDrawingTool( false )
{ {
} }
@ -105,8 +109,16 @@ bool SCH_DRAWING_TOOLS::Init()
return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root(); return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
}; };
auto inDrawingRuleArea =
[&]( const SELECTION& aSel )
{
return m_drawingRuleArea;
};
CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu(); CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu();
ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 ); ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
ctxMenu.AddItem( EE_ACTIONS::closeOutline, inDrawingRuleArea, 200 );
ctxMenu.AddItem( EE_ACTIONS::deleteLastPoint, inDrawingRuleArea, 200 );
return true; return true;
} }
@ -2033,6 +2045,178 @@ int SCH_DRAWING_TOOLS::DrawShape( const TOOL_EVENT& aEvent )
} }
int SCH_DRAWING_TOOLS::DrawRuleArea( const TOOL_EVENT& aEvent )
{
if( m_inDrawingTool )
return 0;
REENTRANCY_GUARD guard( &m_inDrawingTool );
SCOPED_SET_RESET<bool> scopedDrawMode( m_drawingRuleArea, true );
KIGFX::VIEW_CONTROLS* controls = getViewControls();
EE_GRID_HELPER grid( m_toolMgr );
VECTOR2I cursorPos;
RULE_AREA_CREATE_HELPER ruleAreaTool( *getView(), m_frame, m_toolMgr );
POLYGON_GEOM_MANAGER polyGeomMgr( ruleAreaTool );
bool started = false;
// We might be running as the same shape in another co-routine. Make sure that one
// gets whacked.
m_toolMgr->DeactivateTool();
m_toolMgr->RunAction( EE_ACTIONS::clearSelection );
m_frame->PushTool( aEvent );
auto setCursor =
[&]()
{
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
};
auto cleanup = [&]()
{
polyGeomMgr.Reset();
started = false;
getViewControls()->SetAutoPan( false );
getViewControls()->CaptureCursor( false );
m_toolMgr->RunAction( EE_ACTIONS::clearSelection );
};
Activate();
// Must be done after Activate() so that it gets set into the correct context
getViewControls()->ShowCursor( true );
//m_controls->ForceCursorPosition( false );
// Set initial cursor
setCursor();
if( aEvent.HasPosition() )
m_toolMgr->PrimeTool( aEvent.Position() );
// Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() )
{
setCursor();
grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
controls->ForceCursorPosition( true, cursorPos );
polyGeomMgr.SetLeaderMode( m_frame->eeconfig()->m_Drawing.line_mode == LINE_MODE_FREE
? POLYGON_GEOM_MANAGER::LEADER_MODE::DIRECT
: POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 );
if( evt->IsCancelInteractive() )
{
if( started )
{
cleanup();
}
else
{
m_frame->PopTool( aEvent );
// We've handled the cancel event. Don't cancel other tools
evt->SetPassEvent( false );
break;
}
}
else if( evt->IsActivate() )
{
if( started )
cleanup();
if( evt->IsPointEditor() )
{
// don't exit (the point editor runs in the background)
}
else if( evt->IsMoveTool() )
{
// leave ourselves on the stack so we come back after the move
break;
}
else
{
m_frame->PopTool( aEvent );
break;
}
}
else if( evt->IsClick( BUT_RIGHT ) )
{
if( !started )
m_toolMgr->VetoContextMenuMouseWarp();
m_menu.ShowContextMenu( m_selectionTool->GetSelection() );
}
// events that lock in nodes
else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
|| evt->IsAction( &EE_ACTIONS::closeOutline ) )
{
// Check if it is double click / closing line (so we have to finish the zone)
const bool endPolygon = evt->IsDblClick( BUT_LEFT )
|| evt->IsAction( &EE_ACTIONS::closeOutline )
|| polyGeomMgr.NewPointClosesOutline( cursorPos );
if( endPolygon )
{
polyGeomMgr.SetFinished();
polyGeomMgr.Reset();
started = false;
getViewControls()->SetAutoPan( false );
getViewControls()->CaptureCursor( false );
}
// adding a corner
else if( polyGeomMgr.AddPoint( cursorPos ) )
{
if( !started )
{
started = true;
getViewControls()->SetAutoPan( true );
getViewControls()->CaptureCursor( true );
}
}
}
else if( started
&& ( evt->IsAction( &EE_ACTIONS::deleteLastPoint )
|| evt->IsAction( &ACTIONS::doDelete ) || evt->IsAction( &ACTIONS::undo ) ) )
{
if( std::optional<VECTOR2I> last = polyGeomMgr.DeleteLastCorner() )
{
cursorPos = last.value();
getViewControls()->WarpMouseCursor( cursorPos, true );
getViewControls()->ForceCursorPosition( true, cursorPos );
polyGeomMgr.SetCursorPosition( cursorPos );
}
else
{
cleanup();
}
}
else if( started && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
{
polyGeomMgr.SetCursorPosition( cursorPos );
}
else
{
evt->SetPassEvent();
}
} // end while
getViewControls()->SetAutoPan( false );
getViewControls()->CaptureCursor( false );
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
return 0;
}
int SCH_DRAWING_TOOLS::DrawTable( const TOOL_EVENT& aEvent ) int SCH_DRAWING_TOOLS::DrawTable( const TOOL_EVENT& aEvent )
{ {
SCHEMATIC* schematic = getModel<SCHEMATIC>(); SCHEMATIC* schematic = getModel<SCHEMATIC>();
@ -2640,6 +2824,7 @@ void SCH_DRAWING_TOOLS::setTransitions()
Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawCircle.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawCircle.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawArc.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawArc.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawTextBox.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawTextBox.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::DrawRuleArea, EE_ACTIONS::drawRuleArea.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::DrawTable, EE_ACTIONS::drawTable.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::DrawTable, EE_ACTIONS::drawTable.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::PlaceImage, EE_ACTIONS::placeImage.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::PlaceImage, EE_ACTIONS::placeImage.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::ImportGraphics, EE_ACTIONS::importGraphics.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::ImportGraphics, EE_ACTIONS::importGraphics.MakeEvent() );

View File

@ -56,6 +56,7 @@ public:
int SingleClickPlace( const TOOL_EVENT& aEvent ); int SingleClickPlace( const TOOL_EVENT& aEvent );
int TwoClickPlace( const TOOL_EVENT& aEvent ); int TwoClickPlace( const TOOL_EVENT& aEvent );
int DrawShape( const TOOL_EVENT& aEvent ); int DrawShape( const TOOL_EVENT& aEvent );
int DrawRuleArea( const TOOL_EVENT& aEvent );
int DrawTable( const TOOL_EVENT& aEvent ); int DrawTable( const TOOL_EVENT& aEvent );
int DrawSheet( const TOOL_EVENT& aEvent ); int DrawSheet( const TOOL_EVENT& aEvent );
int PlaceImage( const TOOL_EVENT& aEvent ); int PlaceImage( const TOOL_EVENT& aEvent );
@ -103,6 +104,7 @@ private:
STROKE_PARAMS m_lastTextboxStroke; STROKE_PARAMS m_lastTextboxStroke;
wxString m_mruPath; wxString m_mruPath;
bool m_lastAutoLabelRotateOnPlacement; bool m_lastAutoLabelRotateOnPlacement;
bool m_drawingRuleArea;
bool m_inDrawingTool; // Re-entrancy guard bool m_inDrawingTool; // Re-entrancy guard
std::unique_ptr<STATUS_TEXT_POPUP> m_statusPopup; std::unique_ptr<STATUS_TEXT_POPUP> m_statusPopup;

View File

@ -41,6 +41,7 @@
#include <sch_junction.h> #include <sch_junction.h>
#include <sch_line.h> #include <sch_line.h>
#include <sch_marker.h> #include <sch_marker.h>
#include <sch_rule_area.h>
#include <sch_symbol.h> #include <sch_symbol.h>
#include <sch_shape.h> #include <sch_shape.h>
#include <sch_sheet.h> #include <sch_sheet.h>
@ -314,6 +315,7 @@ bool SCH_EDIT_TOOL::Init()
case SCH_GLOBAL_LABEL_T: case SCH_GLOBAL_LABEL_T:
case SCH_HIER_LABEL_T: case SCH_HIER_LABEL_T:
case SCH_DIRECTIVE_LABEL_T: case SCH_DIRECTIVE_LABEL_T:
case SCH_RULE_AREA_T:
case SCH_FIELD_T: case SCH_FIELD_T:
case SCH_SHAPE_T: case SCH_SHAPE_T:
case SCH_BITMAP_T: case SCH_BITMAP_T:
@ -619,6 +621,7 @@ bool SCH_EDIT_TOOL::Init()
const std::vector<KICAD_T> SCH_EDIT_TOOL::RotatableItems = { const std::vector<KICAD_T> SCH_EDIT_TOOL::RotatableItems = {
SCH_SHAPE_T, SCH_SHAPE_T,
SCH_RULE_AREA_T,
SCH_TEXT_T, SCH_TEXT_T,
SCH_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_TABLE_T, SCH_TABLE_T,
@ -769,6 +772,7 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
break; break;
} }
case SCH_RULE_AREA_T:
case SCH_SHAPE_T: case SCH_SHAPE_T:
case SCH_TEXTBOX_T: case SCH_TEXTBOX_T:
head->Rotate( rotPoint, !clockwise ); head->Rotate( rotPoint, !clockwise );
@ -1116,6 +1120,7 @@ int SCH_EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
const std::vector<KICAD_T> swappableItems = { const std::vector<KICAD_T> swappableItems = {
SCH_SHAPE_T, SCH_SHAPE_T,
SCH_RULE_AREA_T,
SCH_TEXT_T, SCH_TEXT_T,
SCH_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_LABEL_T, SCH_LABEL_T,
@ -1359,6 +1364,7 @@ static std::vector<KICAD_T> deletableItems =
SCH_BUS_BUS_ENTRY_T, SCH_BUS_BUS_ENTRY_T,
SCH_BUS_WIRE_ENTRY_T, SCH_BUS_WIRE_ENTRY_T,
SCH_SHAPE_T, SCH_SHAPE_T,
SCH_RULE_AREA_T,
SCH_TEXT_T, SCH_TEXT_T,
SCH_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_TABLECELL_T, // Clear contents SCH_TABLECELL_T, // Clear contents
@ -1434,6 +1440,11 @@ int SCH_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
commit.Modify( item, m_frame->GetScreen() ); commit.Modify( item, m_frame->GetScreen() );
static_cast<SCH_TABLECELL*>( sch_item )->SetText( wxEmptyString ); static_cast<SCH_TABLECELL*>( sch_item )->SetText( wxEmptyString );
} }
else if( sch_item->Type() == SCH_RULE_AREA_T )
{
sch_item->SetFlags( STRUCT_DELETED );
commit.Remove( item, m_frame->GetScreen() );
}
else else
{ {
sch_item->SetFlags( STRUCT_DELETED ); sch_item->SetFlags( STRUCT_DELETED );
@ -1997,6 +2008,15 @@ int SCH_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
break; break;
} }
case SCH_RULE_AREA_T:
{
DIALOG_SHAPE_PROPERTIES dlg( m_frame, static_cast<SCH_SHAPE*>( curr_item ) );
dlg.SetTitle( _( "Rule Area Properties" ) );
dlg.ShowModal();
break;
}
case SCH_LINE_T: case SCH_LINE_T:
case SCH_BUS_WIRE_ENTRY_T: case SCH_BUS_WIRE_ENTRY_T:
case SCH_JUNCTION_T: case SCH_JUNCTION_T:

View File

@ -167,6 +167,7 @@ enum KICAD_T
SCH_LABEL_T, SCH_LABEL_T,
SCH_GLOBAL_LABEL_T, SCH_GLOBAL_LABEL_T,
SCH_HIER_LABEL_T, SCH_HIER_LABEL_T,
SCH_RULE_AREA_T,
SCH_DIRECTIVE_LABEL_T, SCH_DIRECTIVE_LABEL_T,
SCH_SYMBOL_T, SCH_SYMBOL_T,
SCH_SHEET_PIN_T, SCH_SHEET_PIN_T,
@ -373,6 +374,7 @@ constexpr bool IsEeschemaType( const KICAD_T aType )
case SCH_BUS_BUS_ENTRY_T: case SCH_BUS_BUS_ENTRY_T:
case SCH_LINE_T: case SCH_LINE_T:
case SCH_SHAPE_T: case SCH_SHAPE_T:
case SCH_RULE_AREA_T:
case SCH_BITMAP_T: case SCH_BITMAP_T:
case SCH_TEXT_T: case SCH_TEXT_T:
case SCH_TEXTBOX_T: case SCH_TEXTBOX_T:

View File

@ -366,6 +366,7 @@ enum SCH_LAYER_ID: int
LAYER_FIELDS, LAYER_FIELDS,
LAYER_INTERSHEET_REFS, LAYER_INTERSHEET_REFS,
LAYER_NETCLASS_REFS, LAYER_NETCLASS_REFS,
LAYER_RULE_AREAS,
LAYER_DEVICE, LAYER_DEVICE,
LAYER_NOTES, LAYER_NOTES,
LAYER_PRIVATE_NOTES, LAYER_PRIVATE_NOTES,

View File

@ -26,6 +26,7 @@
#include <preview_items/simple_overlay_item.h> #include <preview_items/simple_overlay_item.h>
#include <gal/color4d.h>
#include <geometry/shape_poly_set.h> #include <geometry/shape_poly_set.h>
#include <geometry/shape_line_chain.h> #include <geometry/shape_line_chain.h>
@ -47,6 +48,12 @@ class POLYGON_ITEM : public SIMPLE_OVERLAY_ITEM
public: public:
POLYGON_ITEM(); POLYGON_ITEM();
///< Sets the color of the preview outline
void SetLineColor( KIGFX::COLOR4D lineColor );
///< Sets the color of the outline leader line
void SetLeaderColor( KIGFX::COLOR4D leaderColor );
///< Gets the bounding box of the polygon ///< Gets the bounding box of the polygon
virtual const BOX2I ViewBBox() const override; virtual const BOX2I ViewBBox() const override;
@ -71,6 +78,12 @@ private:
///< polygon fill ///< polygon fill
SHAPE_POLY_SET m_polyfill; SHAPE_POLY_SET m_polyfill;
///< the preview outline color
KIGFX::COLOR4D m_lineColor;
///< the preview leader line color
KIGFX::COLOR4D m_leaderColor;
static const double POLY_LINE_WIDTH; static const double POLY_LINE_WIDTH;
}; };

View File

@ -0,0 +1,376 @@
(kicad_sch
(version 20240417)
(generator "eeschema")
(generator_version "8.99")
(uuid "0726e9d1-eea3-424d-8780-ca27e04db582")
(paper "A4")
(lib_symbols
(symbol "Device:R"
(pin_numbers hide)
(pin_names
(offset 0)
)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(property "Reference" "R"
(at 2.032 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 0 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at -1.778 0 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_keywords" "R res resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_fp_filters" "R_*"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(symbol "R_0_1"
(rectangle
(start -1.016 -2.54)
(end 1.016 2.54)
(stroke
(width 0.254)
(type default)
)
(fill
(type none)
)
)
)
(symbol "R_1_1"
(pin passive line
(at 0 3.81 270)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "1"
(effects
(font
(size 1.27 1.27)
)
)
)
)
(pin passive line
(at 0 -3.81 90)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "2"
(effects
(font
(size 1.27 1.27)
)
)
)
)
)
)
)
(no_connect
(at 121.92 97.79)
(uuid "4236af9f-a6bf-4cf1-9924-15f3612b7e4e")
)
(no_connect
(at 83.82 73.66)
(uuid "5e7b627b-1c2e-465a-84ed-c5ec27af46ab")
)
(wire
(pts
(xy 91.44 73.66) (xy 121.92 73.66)
)
(stroke
(width 0)
(type default)
)
(uuid "73c537ad-8abb-4a42-9ec1-e67712c81b34")
)
(wire
(pts
(xy 121.92 90.17) (xy 121.92 73.66)
)
(stroke
(width 0)
(type default)
)
(uuid "f443e7c4-f627-4cda-b5a1-cbc238e17fb4")
)
(rule_area
(polyline
(pts
(xy 93.98 67.31) (xy 99.06 67.31) (xy 99.06 80.01) (xy 96.52 82.55) (xy 95.25 81.28) (xy 95.25 77.47)
(xy 93.98 76.2)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 40e86e61-b17e-4a50-a591-d1015a45e6e4)
)
)
(rule_area
(polyline
(pts
(xy 133.35 77.47) (xy 133.35 83.82) (xy 114.3 83.82) (xy 111.76 81.28) (xy 111.76 77.47)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid ea7226cb-9108-48d9-9ca3-95d32a5d4077)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 95.25 67.31 0)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left bottom)
)
(uuid "71111a86-8188-4247-ad10-36f2f6d838f8")
(property "Netclass" "CLASS1"
(at 95.9485 64.77 0)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 133.35 80.01 270)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify right bottom)
)
(uuid "e8b709aa-42c8-45a8-8cd0-dd3110e4048f")
(property "Netclass" "CLASS2"
(at 135.89 79.3115 90)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(symbol
(lib_id "Device:R")
(at 121.92 93.98 180)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "e294c19e-e287-4924-9e89-aea9a1a5c8e1")
(property "Reference" "R2"
(at 128.27 93.98 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 125.73 93.98 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 123.698 93.98 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 121.92 93.98 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 121.92 93.98 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "6e8901c6-d0c5-455a-a42b-f31a4c09e3db")
)
(pin "2"
(uuid "fcf2f54f-8f15-40c7-882e-02cb8d2d987f")
)
(instances
(project "RuleAreaNetclassConflictOnWire"
(path "/0726e9d1-eea3-424d-8780-ca27e04db582"
(reference "R2")
(unit 1)
)
)
)
)
(symbol
(lib_id "Device:R")
(at 87.63 73.66 270)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "e33b52ff-7e35-442f-8c36-1e6677209b8c")
(property "Reference" "R1"
(at 87.63 67.31 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 87.63 69.85 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 87.63 71.882 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 87.63 73.66 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 87.63 73.66 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "c87ab3da-a973-4c8f-8e38-3156b231d8af")
)
(pin "2"
(uuid "5d2f6407-4aee-4cc1-850a-883ae2f37307")
)
(instances
(project ""
(path "/0726e9d1-eea3-424d-8780-ca27e04db582"
(reference "R1")
(unit 1)
)
)
)
)
(sheet_instances
(path "/"
(page "1")
)
)
)

View File

@ -0,0 +1,365 @@
(kicad_sch
(version 20240417)
(generator "eeschema")
(generator_version "8.99")
(uuid "0726e9d1-eea3-424d-8780-ca27e04db582")
(paper "A4")
(lib_symbols
(symbol "Device:R"
(pin_numbers hide)
(pin_names
(offset 0)
)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(property "Reference" "R"
(at 2.032 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 0 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at -1.778 0 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_keywords" "R res resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_fp_filters" "R_*"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(symbol "R_0_1"
(rectangle
(start -1.016 -2.54)
(end 1.016 2.54)
(stroke
(width 0.254)
(type default)
)
(fill
(type none)
)
)
)
(symbol "R_1_1"
(pin passive line
(at 0 3.81 270)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "1"
(effects
(font
(size 1.27 1.27)
)
)
)
)
(pin passive line
(at 0 -3.81 90)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "2"
(effects
(font
(size 1.27 1.27)
)
)
)
)
)
)
)
(no_connect
(at 127 73.66)
(uuid "4236af9f-a6bf-4cf1-9924-15f3612b7e4e")
)
(no_connect
(at 83.82 73.66)
(uuid "5e7b627b-1c2e-465a-84ed-c5ec27af46ab")
)
(wire
(pts
(xy 91.44 73.66) (xy 119.38 73.66)
)
(stroke
(width 0)
(type default)
)
(uuid "73c537ad-8abb-4a42-9ec1-e67712c81b34")
)
(rule_area
(polyline
(pts
(xy 106.68 67.31) (xy 110.49 67.31) (xy 110.49 77.47) (xy 106.68 77.47)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 03801fed-03b2-45ff-96c8-aae8ef0df963)
)
)
(rule_area
(polyline
(pts
(xy 93.98 67.31) (xy 97.79 67.31) (xy 97.79 80.01) (xy 93.98 80.01)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 6fd89307-6035-4c4e-8858-d37921436305)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 95.25 67.31 0)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left bottom)
)
(uuid "71111a86-8188-4247-ad10-36f2f6d838f8")
(property "Netclass" "CLASS1"
(at 95.9485 64.77 0)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 107.95 67.31 0)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left bottom)
)
(uuid "e8b709aa-42c8-45a8-8cd0-dd3110e4048f")
(property "Netclass" "CLASS2"
(at 108.6485 64.77 0)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(symbol
(lib_id "Device:R")
(at 123.19 73.66 270)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "e294c19e-e287-4924-9e89-aea9a1a5c8e1")
(property "Reference" "R2"
(at 123.19 67.31 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 123.19 69.85 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 123.19 71.882 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 123.19 73.66 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 123.19 73.66 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "6e8901c6-d0c5-455a-a42b-f31a4c09e3db")
)
(pin "2"
(uuid "fcf2f54f-8f15-40c7-882e-02cb8d2d987f")
)
(instances
(project "RuleAreaNetclassConflictOnWire"
(path "/0726e9d1-eea3-424d-8780-ca27e04db582"
(reference "R2")
(unit 1)
)
)
)
)
(symbol
(lib_id "Device:R")
(at 87.63 73.66 270)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "e33b52ff-7e35-442f-8c36-1e6677209b8c")
(property "Reference" "R1"
(at 87.63 67.31 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 87.63 69.85 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 87.63 71.882 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 87.63 73.66 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 87.63 73.66 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "c87ab3da-a973-4c8f-8e38-3156b231d8af")
)
(pin "2"
(uuid "5d2f6407-4aee-4cc1-850a-883ae2f37307")
)
(instances
(project ""
(path "/0726e9d1-eea3-424d-8780-ca27e04db582"
(reference "R1")
(unit 1)
)
)
)
)
(sheet_instances
(path "/"
(page "1")
)
)
)

View File

@ -0,0 +1,45 @@
(kicad_sch
(version 20240417)
(generator "eeschema")
(generator_version "8.99")
(uuid "e77939c4-758d-4d0c-a6e5-dc441c8c54c9")
(paper "A4")
(lib_symbols)
(rule_area
(polyline
(pts
(xy 144.78 63.5) (xy 177.8 63.5) (xy 180.34 66.04) (xy 180.34 110.49) (xy 171.45 110.49) (xy 157.48 96.52)
(xy 148.59 105.41) (xy 148.59 107.95) (xy 133.35 92.71) (xy 133.35 85.09) (xy 139.7 78.74) (xy 139.7 68.58)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 4f0aecc0-f3b3-4645-a47e-6a29fb5ff671)
)
)
(rule_area
(polyline
(pts
(xy 69.85 49.53) (xy 101.6 49.53) (xy 101.6 73.66) (xy 95.25 80.01) (xy 86.36 80.01) (xy 76.2 69.85)
(xy 76.2 66.04) (xy 78.74 63.5) (xy 69.85 54.61)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 839de646-0221-4c81-b248-242a273d8ed3)
)
)
(sheet_instances
(path "/"
(page "1")
)
)
)

View File

@ -0,0 +1,327 @@
(kicad_sch
(version 20240417)
(generator "eeschema")
(generator_version "8.99")
(uuid "8a90b8e2-28c2-4028-bcb6-cef3be983f1e")
(paper "A4")
(lib_symbols
(symbol "Device:R"
(pin_numbers hide)
(pin_names
(offset 0)
)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(property "Reference" "R"
(at 2.032 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 0 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at -1.778 0 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_keywords" "R res resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_fp_filters" "R_*"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(symbol "R_0_1"
(rectangle
(start -1.016 -2.54)
(end 1.016 2.54)
(stroke
(width 0.254)
(type default)
)
(fill
(type none)
)
)
)
(symbol "R_1_1"
(pin passive line
(at 0 3.81 270)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "1"
(effects
(font
(size 1.27 1.27)
)
)
)
)
(pin passive line
(at 0 -3.81 90)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "2"
(effects
(font
(size 1.27 1.27)
)
)
)
)
)
)
)
(no_connect
(at 132.08 53.34)
(uuid "45692886-21e1-4796-b1b4-634d6c7163d5")
)
(no_connect
(at 83.82 53.34)
(uuid "c283f30d-202c-4a0d-9d0a-ea95c5656841")
)
(wire
(pts
(xy 91.44 53.34) (xy 124.46 53.34)
)
(stroke
(width 0)
(type default)
)
(uuid "6f61af9e-a21c-4ea8-aac1-554407fe006a")
)
(rule_area
(polyline
(pts
(xy 99.06 44.45) (xy 105.41 44.45) (xy 105.41 60.96) (xy 99.06 60.96)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 01d7705f-5c3d-4abe-b2c7-9e8f5b00caa8)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 101.6 44.45 0)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left bottom)
)
(uuid "655ca652-695a-4f6a-93fa-4347d69a2f15")
(property "Netclass" "CLASS1"
(at 102.2985 41.91 0)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(symbol
(lib_id "Device:R")
(at 87.63 53.34 270)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "57d8460e-6d78-4dc9-8734-201edb21294a")
(property "Reference" "R1"
(at 87.63 46.99 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 87.63 49.53 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 87.63 51.562 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 87.63 53.34 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 87.63 53.34 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "5d7b48cb-ccac-454c-b8ae-d8106594e160")
)
(pin "2"
(uuid "e59c83d5-3e67-4d97-8414-98cf0d4cd0f7")
)
(instances
(project ""
(path "/8a90b8e2-28c2-4028-bcb6-cef3be983f1e"
(reference "R1")
(unit 1)
)
)
)
)
(symbol
(lib_id "Device:R")
(at 128.27 53.34 270)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "758cfdea-5424-4d58-a623-ef6afa897cdc")
(property "Reference" "R2"
(at 128.27 46.99 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 128.27 49.53 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 128.27 51.562 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 128.27 53.34 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 128.27 53.34 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "fc325f46-cf90-477d-b24e-842cfcdab056")
)
(pin "2"
(uuid "d48f9df0-ba21-474c-878e-433fd5cecebf")
)
(instances
(project "RuleAreaOneNetclassDirective"
(path "/8a90b8e2-28c2-4028-bcb6-cef3be983f1e"
(reference "R2")
(unit 1)
)
)
)
)
(sheet_instances
(path "/"
(page "1")
)
)
)

View File

@ -0,0 +1,43 @@
(kicad_sch
(version 20240417)
(generator "eeschema")
(generator_version "8.99")
(uuid "e77939c4-758d-4d0c-a6e5-dc441c8c54c9")
(paper "A4")
(lib_symbols)
(rule_area
(polyline
(pts
(xy 81.28 64.77) (xy 107.95 64.77) (xy 107.95 97.79) (xy 106.68 99.06) (xy 100.33 99.06) (xy 81.28 80.01)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 29482117-50fb-4bf0-9227-b57a2a024196)
)
)
(rule_area
(polyline
(pts
(xy 63.5 48.26) (xy 95.25 48.26) (xy 95.25 76.2) (xy 92.71 78.74) (xy 67.31 78.74) (xy 63.5 74.93)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid fb9e0dd5-7b94-4714-b095-086e21d4076e)
)
)
(sheet_instances
(path "/"
(page "1")
)
)
)

View File

@ -0,0 +1,75 @@
(kicad_sch
(version 20240417)
(generator "eeschema")
(generator_version "8.99")
(uuid "e77939c4-758d-4d0c-a6e5-dc441c8c54c9")
(paper "A4")
(lib_symbols)
(rule_area
(polyline
(pts
(xy 193.04 80.01) (xy 229.87 80.01) (xy 231.14 81.28) (xy 231.14 111.76) (xy 205.74 111.76) (xy 199.39 105.41)
(xy 199.39 102.87) (xy 193.04 96.52)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 205fcd89-40f4-4d53-8543-c72a408467cf)
)
)
(rule_area
(polyline
(pts
(xy 215.9 100.33) (xy 215.9 135.89) (xy 250.19 135.89) (xy 255.27 130.81) (xy 255.27 109.22) (xy 246.38 100.33)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 4953ad1a-332e-4324-a6e9-44125580b5ce)
)
)
(rule_area
(polyline
(pts
(xy 90.17 52.07) (xy 64.77 52.07) (xy 64.77 71.12) (xy 73.66 80.01) (xy 77.47 80.01) (xy 90.17 67.31)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 9e60651e-f0c3-4ab3-88c0-5b67a7585ce9)
)
)
(rule_area
(polyline
(pts
(xy 80.01 66.04) (xy 107.95 66.04) (xy 110.49 68.58) (xy 110.49 100.33) (xy 85.09 100.33) (xy 74.93 90.17)
(xy 74.93 71.12)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid a2990ee5-6b66-496f-a7b1-0402651214fa)
)
)
(sheet_instances
(path "/"
(page "1")
)
)
)

View File

@ -0,0 +1,373 @@
(kicad_sch
(version 20240417)
(generator "eeschema")
(generator_version "8.99")
(uuid "3faa707b-1d78-466d-bafe-1ee08b43bb08")
(paper "A4")
(lib_symbols
(symbol "Device:R"
(pin_numbers hide)
(pin_names
(offset 0)
)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(property "Reference" "R"
(at 2.032 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 0 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at -1.778 0 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_keywords" "R res resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_fp_filters" "R_*"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(symbol "R_0_1"
(rectangle
(start -1.016 -2.54)
(end 1.016 2.54)
(stroke
(width 0.254)
(type default)
)
(fill
(type none)
)
)
)
(symbol "R_1_1"
(pin passive line
(at 0 3.81 270)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "1"
(effects
(font
(size 1.27 1.27)
)
)
)
)
(pin passive line
(at 0 -3.81 90)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "2"
(effects
(font
(size 1.27 1.27)
)
)
)
)
)
)
)
(no_connect
(at 88.9 74.93)
(uuid "5833ab2c-0b21-4284-bda0-ec7a7f3886e3")
)
(no_connect
(at 137.16 74.93)
(uuid "6a8eab8a-8b70-48aa-8775-bd58e38e6544")
)
(wire
(pts
(xy 96.52 74.93) (xy 129.54 74.93)
)
(stroke
(width 0)
(type default)
)
(uuid "3c913039-c0ff-4276-9bfd-95aa6d609814")
)
(rule_area
(polyline
(pts
(xy 102.87 66.04) (xy 119.38 66.04) (xy 119.38 78.74) (xy 113.03 85.09) (xy 107.95 85.09) (xy 102.87 80.01)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 732edf9e-56d8-43fc-b7ec-e3df2ffeb182)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 106.68 66.04 0)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left bottom)
)
(uuid "0e535a38-1e87-423a-9462-046eeca2761f")
(property "Netclass" "CLASS1"
(at 107.3785 63.5 0)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 115.57 66.04 0)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left bottom)
)
(uuid "3651b727-06a6-4517-b594-14249bcb01ff")
(property "Netclass" "CLASS2"
(at 116.2685 63.5 0)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 111.76 85.09 180)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify right bottom)
)
(uuid "39c91c96-4582-476e-aaa8-0403610211a4")
(property "Netclass" "CLASS3"
(at 112.4585 87.63 0)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(symbol
(lib_id "Device:R")
(at 133.35 74.93 270)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "69906541-660f-49dd-b971-79ef911d51f2")
(property "Reference" "R2"
(at 133.35 68.58 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 133.35 71.12 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 133.35 73.152 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 133.35 74.93 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 133.35 74.93 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "5a4f2edd-e02e-4a2a-b273-2a79268c7b9b")
)
(pin "2"
(uuid "92e081c4-e86d-400c-82e1-d46671606b34")
)
(instances
(project "RuleAreaThreeNetclassDirectives"
(path "/3faa707b-1d78-466d-bafe-1ee08b43bb08"
(reference "R2")
(unit 1)
)
)
)
)
(symbol
(lib_id "Device:R")
(at 92.71 74.93 270)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "6c332818-966e-43a5-87c5-6aea83712c35")
(property "Reference" "R1"
(at 92.71 68.58 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 92.71 71.12 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 92.71 73.152 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 92.71 74.93 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 92.71 74.93 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "50fab8cc-532c-479e-a764-1688c768c001")
)
(pin "2"
(uuid "0f5fce2a-437e-4928-b1e0-0469819dd910")
)
(instances
(project "RuleAreaThreeNetclassDirectives"
(path "/3faa707b-1d78-466d-bafe-1ee08b43bb08"
(reference "R1")
(unit 1)
)
)
)
)
(sheet_instances
(path "/"
(page "1")
)
)
)

View File

@ -0,0 +1,350 @@
(kicad_sch
(version 20240417)
(generator "eeschema")
(generator_version "8.99")
(uuid "72af7883-b930-45a7-b8c1-7781d1afdd37")
(paper "A4")
(lib_symbols
(symbol "Device:R"
(pin_numbers hide)
(pin_names
(offset 0)
)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(property "Reference" "R"
(at 2.032 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 0 0 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at -1.778 0 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_keywords" "R res resistor"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "ki_fp_filters" "R_*"
(at 0 0 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(symbol "R_0_1"
(rectangle
(start -1.016 -2.54)
(end 1.016 2.54)
(stroke
(width 0.254)
(type default)
)
(fill
(type none)
)
)
)
(symbol "R_1_1"
(pin passive line
(at 0 3.81 270)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "1"
(effects
(font
(size 1.27 1.27)
)
)
)
)
(pin passive line
(at 0 -3.81 90)
(length 1.27)
(name "~"
(effects
(font
(size 1.27 1.27)
)
)
)
(number "2"
(effects
(font
(size 1.27 1.27)
)
)
)
)
)
)
)
(no_connect
(at 106.68 71.12)
(uuid "2f717211-60fa-4046-b14f-c148c1bebb31")
)
(no_connect
(at 154.94 71.12)
(uuid "e58e3d56-33f2-47c1-8169-9b603a68c30f")
)
(wire
(pts
(xy 114.3 71.12) (xy 147.32 71.12)
)
(stroke
(width 0)
(type default)
)
(uuid "2d14d2f0-6ae7-41c8-8699-c57748f8f4ae")
)
(rule_area
(polyline
(pts
(xy 121.92 62.23) (xy 137.16 62.23) (xy 137.16 73.66) (xy 135.89 74.93) (xy 123.19 74.93) (xy 121.92 73.66)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid 826526a6-b643-4832-8cb3-7693aac87471)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 133.35 62.23 0)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left bottom)
)
(uuid "0318db31-1e4c-4d69-8534-0e5f3ee9c7eb")
(property "Netclass" "CLASS2"
(at 134.0485 59.69 0)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(netclass_flag ""
(length 2.54)
(shape round)
(at 124.46 62.23 0)
(fields_autoplaced yes)
(effects
(font
(size 1.27 1.27)
)
(justify left bottom)
)
(uuid "74dc4bc7-6913-49ba-a2f3-bcdc39c3019f")
(property "Netclass" "CLASS1"
(at 125.1585 59.69 0)
(effects
(font
(size 1.27 1.27)
(italic yes)
)
(justify left)
)
)
)
(symbol
(lib_id "Device:R")
(at 151.13 71.12 270)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "4f5c367d-1c08-48f1-86dc-e95b0140a51b")
(property "Reference" "R2"
(at 151.13 64.77 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 151.13 67.31 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 151.13 69.342 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 151.13 71.12 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 151.13 71.12 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "dbe85168-ed53-4e8a-8c45-277d6c150cde")
)
(pin "2"
(uuid "4c070690-f1aa-48d2-a083-8c7fe39df9c2")
)
(instances
(project "RuleAreaTwoNetclassDirectives"
(path "/72af7883-b930-45a7-b8c1-7781d1afdd37"
(reference "R2")
(unit 1)
)
)
)
)
(symbol
(lib_id "Device:R")
(at 110.49 71.12 270)
(unit 1)
(exclude_from_sim no)
(in_bom yes)
(on_board yes)
(dnp no)
(fields_autoplaced yes)
(uuid "7848d115-602f-44c3-b980-c1e03934ea7e")
(property "Reference" "R1"
(at 110.49 64.77 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Value" "R"
(at 110.49 67.31 90)
(effects
(font
(size 1.27 1.27)
)
)
)
(property "Footprint" ""
(at 110.49 69.342 90)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Datasheet" "~"
(at 110.49 71.12 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(property "Description" "Resistor"
(at 110.49 71.12 0)
(effects
(font
(size 1.27 1.27)
)
(hide yes)
)
)
(pin "1"
(uuid "84a25105-1263-4adf-a0a5-a2bdf51e736e")
)
(pin "2"
(uuid "4d2f1a67-27d6-4ef0-a95f-9a34d0373e7d")
)
(instances
(project "RuleAreaTwoNetclassDirectives"
(path "/72af7883-b930-45a7-b8c1-7781d1afdd37"
(reference "R1")
(unit 1)
)
)
)
)
(sheet_instances
(path "/"
(page "1")
)
)
)

View File

@ -0,0 +1,58 @@
(kicad_sch
(version 20240417)
(generator "eeschema")
(generator_version "8.99")
(uuid "e77939c4-758d-4d0c-a6e5-dc441c8c54c9")
(paper "A4")
(lib_symbols)
(rule_area
(polyline
(pts
(xy 105.41 66.04) (xy 105.41 95.25) (xy 124.46 95.25) (xy 133.35 86.36) (xy 133.35 83.82) (xy 115.57 66.04)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid b2e29650-5d7b-46fa-b3ac-2da8c988ba4f)
)
)
(rule_area
(polyline
(pts
(xy 85.09 76.2) (xy 114.3 76.2) (xy 114.3 107.95) (xy 92.71 107.95) (xy 85.09 100.33)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid c2d18c36-f42f-4d71-b979-aec0f5842e3b)
)
)
(rule_area
(polyline
(pts
(xy 68.58 60.96) (xy 96.52 60.96) (xy 97.79 62.23) (xy 97.79 88.9) (xy 76.2 88.9) (xy 68.58 81.28)
)
(stroke
(width 0)
(type dash)
)
(fill
(type none)
)
(uuid d4219527-beea-4857-99ad-9080af58cbc4)
)
)
(sheet_instances
(path "/"
(page "1")
)
)
)

View File

@ -56,6 +56,7 @@ set( QA_EESCHEMA_SRCS
erc/test_erc_global_labels.cpp erc/test_erc_global_labels.cpp
erc/test_erc_no_connect.cpp erc/test_erc_no_connect.cpp
erc/test_erc_hierarchical_schematics.cpp erc/test_erc_hierarchical_schematics.cpp
erc/test_erc_rule_areas.cpp
test_eagle_plugin.cpp test_eagle_plugin.cpp
test_lib_part.cpp test_lib_part.cpp

View File

@ -0,0 +1,139 @@
/*
* 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 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one at
* http://www.gnu.org/licenses/
*/
#include <qa_utils/wx_utils/unit_test_utils.h>
#include <schematic_utils/schematic_file_util.h>
#include <connection_graph.h>
#include <schematic.h>
#include <erc_settings.h>
#include <erc.h>
#include <erc_report.h>
#include <sch_rule_area.h>
#include <settings/settings_manager.h>
#include <locale_io.h>
struct ERC_REGRESSION_TEST_FIXTURE
{
ERC_REGRESSION_TEST_FIXTURE() : m_settingsManager( true /* headless */ ) {}
SETTINGS_MANAGER m_settingsManager;
std::unique_ptr<SCHEMATIC> m_schematic;
};
BOOST_FIXTURE_TEST_CASE( ERCRuleAreaNetClasseDirectives, ERC_REGRESSION_TEST_FIXTURE )
{
LOCALE_IO dummy;
// Check for Errors when using rule area netclass directives
std::vector<std::pair<wxString, int>> tests = { { "RuleAreaOneNetclassDirective", 0 },
{ "RuleAreaTwoNetclassDirectives", 1 },
{ "RuleAreaThreeNetclassDirectives", 2 },
{ "RuleAreaNetclassConflictOnWire_1", 1 },
{ "RuleAreaNetclassConflictOnWire_2", 1 } };
for( const std::pair<wxString, int>& test : tests )
{
KI_TEST::LoadSchematic( m_settingsManager, test.first, m_schematic );
ERC_SETTINGS& settings = m_schematic->ErcSettings();
SHEETLIST_ERC_ITEMS_PROVIDER errors( m_schematic.get() );
// Skip the "Modified symbol" warning
settings.m_ERCSeverities[ERCE_LIB_SYMBOL_ISSUES] = RPT_SEVERITY_IGNORE;
settings.m_ERCSeverities[ERCE_LIB_SYMBOL_MISMATCH] = RPT_SEVERITY_IGNORE;
// Configure the rules under test
settings.m_ERCSeverities[ERCE_NETCLASS_CONFLICT] = RPT_SEVERITY_ERROR;
std::unordered_set<SCH_SCREEN*> allScreens;
SCH_SCREENS screens( m_schematic->Root() );
screens.BuildClientSheetPathList();
for( SCH_SCREEN* screen = screens.GetFirst(); screen != nullptr;
screen = screens.GetNext() )
allScreens.insert( screen );
SCH_RULE_AREA::UpdateRuleAreasInScreens( allScreens, nullptr );
m_schematic->ConnectionGraph()->Recalculate( m_schematic->GetSheets(), true );
m_schematic->ConnectionGraph()->RunERC();
errors.SetSeverities( RPT_SEVERITY_ERROR | RPT_SEVERITY_WARNING );
ERC_REPORT reportWriter( m_schematic.get(), EDA_UNITS::MILLIMETRES );
BOOST_CHECK_MESSAGE( errors.GetCount() == test.second,
"Expected " << test.second << " errors in " << test.first.ToStdString()
<< " but got " << errors.GetCount() << "\n"
<< reportWriter.GetTextReport() );
}
}
BOOST_FIXTURE_TEST_CASE( ERCRuleAreaOverlaps, ERC_REGRESSION_TEST_FIXTURE )
{
LOCALE_IO dummy;
// Check for Errors when using rule area netclass directives
std::vector<std::pair<wxString, int>> tests = { { "RuleAreaNoOverlap", 0 },
{ "RuleAreaOneOverlap", 1 },
{ "RuleAreaOneOverlapTwice", 2 },
{ "RuleAreaTwoOverlaps", 2 } };
for( const std::pair<wxString, int>& test : tests )
{
KI_TEST::LoadSchematic( m_settingsManager, test.first, m_schematic );
ERC_SETTINGS& settings = m_schematic->ErcSettings();
SHEETLIST_ERC_ITEMS_PROVIDER errors( m_schematic.get() );
// Skip the "Modified symbol" warning
settings.m_ERCSeverities[ERCE_LIB_SYMBOL_ISSUES] = RPT_SEVERITY_IGNORE;
settings.m_ERCSeverities[ERCE_LIB_SYMBOL_MISMATCH] = RPT_SEVERITY_IGNORE;
// Configure the rules under test
settings.m_ERCSeverities[ERCE_OVERLAPPING_RULE_AREAS] = RPT_SEVERITY_ERROR;
std::unordered_set<SCH_SCREEN*> allScreens;
SCH_SCREENS screens( m_schematic->Root() );
screens.BuildClientSheetPathList();
for( SCH_SCREEN* screen = screens.GetFirst(); screen != nullptr;
screen = screens.GetNext() )
allScreens.insert( screen );
SCH_RULE_AREA::UpdateRuleAreasInScreens( allScreens, nullptr );
m_schematic->ConnectionGraph()->Recalculate( m_schematic->GetSheets(), true );
ERC_TESTER tester( m_schematic.get() );
tester.RunRuleAreaERC();
errors.SetSeverities( RPT_SEVERITY_ERROR | RPT_SEVERITY_WARNING );
ERC_REPORT reportWriter( m_schematic.get(), EDA_UNITS::MILLIMETRES );
BOOST_CHECK_MESSAGE( errors.GetCount() == test.second,
"Expected " << test.second << " errors in " << test.first.ToStdString()
<< " but got " << errors.GetCount() << "\n"
<< reportWriter.GetTextReport() );
}
}

View File

@ -33,6 +33,7 @@
#include <sch_no_connect.h> #include <sch_no_connect.h>
#include <sch_bus_entry.h> #include <sch_bus_entry.h>
#include <sch_line.h> #include <sch_line.h>
#include <sch_rule_area.h>
#include <sch_shape.h> #include <sch_shape.h>
#include <sch_bitmap.h> #include <sch_bitmap.h>
#include <sch_text.h> #include <sch_text.h>
@ -81,6 +82,24 @@ public:
case SCH_BUS_WIRE_ENTRY_T: return new SCH_BUS_WIRE_ENTRY(); case SCH_BUS_WIRE_ENTRY_T: return new SCH_BUS_WIRE_ENTRY();
case SCH_BUS_BUS_ENTRY_T: return new SCH_BUS_BUS_ENTRY(); case SCH_BUS_BUS_ENTRY_T: return new SCH_BUS_BUS_ENTRY();
case SCH_LINE_T: return new SCH_LINE(); case SCH_LINE_T: return new SCH_LINE();
case SCH_RULE_AREA_T:
{
SHAPE_POLY_SET ruleShape;
ruleShape.NewOutline();
auto& outline = ruleShape.Outline( 0 );
outline.Append( VECTOR2I( 20000, 20000) );
outline.Append( VECTOR2I( 22000, 20000) );
outline.Append( VECTOR2I( 22000, 22000) );
outline.Append( VECTOR2I( 20000, 22000) );
outline.SetClosed( true );
outline.Simplify( true );
SCH_RULE_AREA* ruleArea = new SCH_RULE_AREA();
ruleArea->SetPolyShape( ruleShape );
return ruleArea;
}
case SCH_SHAPE_T: return new SCH_SHAPE( SHAPE_T::ARC, LAYER_NOTES ); case SCH_SHAPE_T: return new SCH_SHAPE( SHAPE_T::ARC, LAYER_NOTES );
case SCH_BITMAP_T: return new SCH_BITMAP(); case SCH_BITMAP_T: return new SCH_BITMAP();
case SCH_TEXT_T: return new SCH_TEXT( VECTOR2I( 0, 0 ), "test text" ); case SCH_TEXT_T: return new SCH_TEXT( VECTOR2I( 0, 0 ), "test text" );