7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-07 00:25:22 +00:00
kicad/pcbnew/pcb_marker.cpp
Seth Hillbrand 0b2d4d4879 Revise Copyright statement to align with TLF
Recommendation is to avoid using the year nomenclature as this
information is already encoded in the git repo.  Avoids needing to
repeatly update.

Also updates AUTHORS.txt from current repo with contributor names
2025-01-01 14:12:04 -08:00

385 lines
12 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright The 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 <bitmaps.h>
#include <base_units.h>
#include <eda_draw_frame.h>
#include <board.h>
#include <board_design_settings.h>
#include <pcb_marker.h>
#include <layer_ids.h>
#include <settings/color_settings.h>
#include <settings/settings_manager.h>
#include <geometry/shape_null.h>
#include <widgets/ui_common.h>
#include <pgm_base.h>
#include <drc/drc_item.h>
#include <trigo.h>
/// Factor to convert the maker unit shape to internal units:
#define SCALING_FACTOR pcbIUScale.mmToIU( 0.1625 )
PCB_MARKER::PCB_MARKER( std::shared_ptr<RC_ITEM> aItem, const VECTOR2I& aPosition, int aLayer ) :
BOARD_ITEM( nullptr, PCB_MARKER_T, F_Cu ), // parent set during BOARD::Add()
MARKER_BASE( SCALING_FACTOR, aItem )
{
if( m_rcItem )
{
m_rcItem->SetParent( this );
if( aLayer == LAYER_DRAWINGSHEET )
{
SetMarkerType( MARKER_BASE::MARKER_DRAWING_SHEET );
}
else
{
switch( m_rcItem->GetErrorCode() )
{
case DRCE_UNCONNECTED_ITEMS:
SetMarkerType( MARKER_BASE::MARKER_RATSNEST );
break;
case DRCE_MISSING_FOOTPRINT:
case DRCE_DUPLICATE_FOOTPRINT:
case DRCE_EXTRA_FOOTPRINT:
case DRCE_NET_CONFLICT:
case DRCE_SCHEMATIC_PARITY:
case DRCE_FOOTPRINT_FILTERS:
SetMarkerType( MARKER_BASE::MARKER_PARITY );
break;
default:
SetMarkerType( MARKER_BASE::MARKER_DRC );
break;
}
SetLayer( ToLAYER_ID( aLayer ) );
}
}
m_Pos = aPosition;
}
/* destructor */
PCB_MARKER::~PCB_MARKER()
{
if( m_rcItem )
m_rcItem->SetParent( nullptr );
}
wxString PCB_MARKER::SerializeToString() const
{
if( m_rcItem->GetErrorCode() == DRCE_COPPER_SLIVER
|| m_rcItem->GetErrorCode() == DRCE_GENERIC_WARNING
|| m_rcItem->GetErrorCode() == DRCE_GENERIC_ERROR )
{
return wxString::Format( wxT( "%s|%d|%d|%s|%s" ),
m_rcItem->GetSettingsKey(),
m_Pos.x,
m_Pos.y,
m_rcItem->GetMainItemID().AsString(),
LayerName( m_layer ) );
}
else if( m_rcItem->GetErrorCode() == DRCE_STARVED_THERMAL )
{
return wxString::Format( wxT( "%s|%d|%d|%s|%s|%s" ),
m_rcItem->GetSettingsKey(),
m_Pos.x,
m_Pos.y,
m_rcItem->GetMainItemID().AsString(),
m_rcItem->GetAuxItemID().AsString(),
LayerName( m_layer ) );
}
else if( m_rcItem->GetErrorCode() == DRCE_UNRESOLVED_VARIABLE
&& m_rcItem->GetParent()->GetMarkerType() == MARKER_DRAWING_SHEET )
{
return wxString::Format( wxT( "%s|%d|%d|%s|%s" ),
m_rcItem->GetSettingsKey(),
m_Pos.x,
m_Pos.y,
// Drawing sheet KIIDs aren't preserved between runs
wxEmptyString,
wxEmptyString );
}
else
{
return wxString::Format( wxT( "%s|%d|%d|%s|%s" ),
m_rcItem->GetSettingsKey(),
m_Pos.x,
m_Pos.y,
m_rcItem->GetMainItemID().AsString(),
m_rcItem->GetAuxItemID().AsString() );
}
}
PCB_MARKER* PCB_MARKER::DeserializeFromString( const wxString& data )
{
auto getMarkerLayer =
[]( const wxString& layerName ) -> int
{
for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
{
if( LayerName( ToLAYER_ID( layer ) ) == layerName )
return layer;
}
return F_Cu;
};
wxArrayString props = wxSplit( data, '|' );
int markerLayer = F_Cu;
VECTOR2I markerPos( (int) strtol( props[1].c_str(), nullptr, 10 ),
(int) strtol( props[2].c_str(), nullptr, 10 ) );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( props[0] );
if( !drcItem )
return nullptr;
if( drcItem->GetErrorCode() == DRCE_COPPER_SLIVER
|| drcItem->GetErrorCode() == DRCE_GENERIC_WARNING
|| drcItem->GetErrorCode() == DRCE_GENERIC_ERROR )
{
drcItem->SetItems( KIID( props[3] ) );
markerLayer = getMarkerLayer( props[4] );
}
else if( drcItem->GetErrorCode() == DRCE_STARVED_THERMAL )
{
drcItem->SetItems( KIID( props[3] ), KIID( props[4] ) );
// Pre-7.0 versions didn't differentiate between layers
if( props.size() == 6 )
markerLayer = getMarkerLayer( props[5] );
}
else if( drcItem->GetErrorCode() == DRCE_UNRESOLVED_VARIABLE
&& props[3].IsEmpty() && props[4].IsEmpty() )
{
// Note: caller must load our item pointer with the drawing sheet proxy item
markerLayer = LAYER_DRAWINGSHEET;
}
else
{
drcItem->SetItems( KIID( props[3] ), KIID( props[4] ) );
}
return new PCB_MARKER( drcItem, markerPos, markerLayer );
}
void PCB_MARKER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
{
aList.emplace_back( _( "Type" ), _( "Marker" ) );
aList.emplace_back( _( "Violation" ), m_rcItem->GetErrorMessage() );
switch( GetSeverity() )
{
case RPT_SEVERITY_IGNORE:
aList.emplace_back( _( "Severity" ), _( "Ignore" ) );
break;
case RPT_SEVERITY_WARNING:
aList.emplace_back( _( "Severity" ), _( "Warning" ) );
break;
case RPT_SEVERITY_ERROR:
aList.emplace_back( _( "Severity" ), _( "Error" ) );
break;
default:
break;
}
if( GetMarkerType() == MARKER_DRAWING_SHEET )
{
aList.emplace_back( _( "Drawing Sheet" ), wxEmptyString );
}
else
{
wxString mainText;
wxString auxText;
EDA_ITEM* mainItem = nullptr;
EDA_ITEM* auxItem = nullptr;
if( m_rcItem->GetMainItemID() != niluuid )
mainItem = aFrame->GetItem( m_rcItem->GetMainItemID() );
if( m_rcItem->GetAuxItemID() != niluuid )
auxItem = aFrame->GetItem( m_rcItem->GetAuxItemID() );
if( mainItem )
mainText = mainItem->GetItemDescription( aFrame, true );
if( auxItem )
auxText = auxItem->GetItemDescription( aFrame, true );
aList.emplace_back( mainText, auxText );
}
if( IsExcluded() )
aList.emplace_back( _( "Excluded" ), m_comment );
}
void PCB_MARKER::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
{
// Marker geometry isn't user-editable
}
void PCB_MARKER::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
{
// Marker geometry isn't user-editable
}
std::shared_ptr<SHAPE> PCB_MARKER::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
{
// Markers do not participate in the board geometry space, and therefore have no
// effectiven shape.
return std::make_shared<SHAPE_NULL>();
}
wxString PCB_MARKER::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
{
return wxString::Format( _( "Marker (%s)" ),
aFull ? m_rcItem->GetErrorMessage() : m_rcItem->GetErrorText() );
}
BITMAPS PCB_MARKER::GetMenuImage() const
{
return BITMAPS::drc;
}
SEVERITY PCB_MARKER::GetSeverity() const
{
if( IsExcluded() )
return RPT_SEVERITY_EXCLUSION;
DRC_ITEM* item = static_cast<DRC_ITEM*>( m_rcItem.get() );
if( item->GetErrorCode() == DRCE_GENERIC_WARNING )
return RPT_SEVERITY_WARNING;
else if( item->GetErrorCode() == DRCE_GENERIC_ERROR )
return RPT_SEVERITY_ERROR;
DRC_RULE* rule = item->GetViolatingRule();
if( rule && rule->m_Severity != RPT_SEVERITY_UNDEFINED )
return rule->m_Severity;
return GetBoard()->GetDesignSettings().GetSeverity( item->GetErrorCode() );
}
std::vector<int> PCB_MARKER::ViewGetLayers() const
{
if( GetMarkerType() == MARKER_RATSNEST )
{
return {};
}
std::vector<int> layers{ 0, LAYER_MARKER_SHADOWS, LAYER_DRC_SHAPE1, LAYER_DRC_SHAPE2 };
switch( GetSeverity() )
{
default:
case SEVERITY::RPT_SEVERITY_ERROR: layers[0] = LAYER_DRC_ERROR; break;
case SEVERITY::RPT_SEVERITY_WARNING: layers[0] = LAYER_DRC_WARNING; break;
case SEVERITY::RPT_SEVERITY_EXCLUSION: layers[0] = LAYER_DRC_EXCLUSION; break;
}
return layers;
}
GAL_LAYER_ID PCB_MARKER::GetColorLayer() const
{
switch( GetSeverity() )
{
default:
case SEVERITY::RPT_SEVERITY_ERROR: return LAYER_DRC_ERROR;
case SEVERITY::RPT_SEVERITY_WARNING: return LAYER_DRC_WARNING;
case SEVERITY::RPT_SEVERITY_EXCLUSION: return LAYER_DRC_EXCLUSION;
}
}
KIGFX::COLOR4D PCB_MARKER::getColor() const
{
COLOR_SETTINGS* colors = Pgm().GetSettingsManager().GetColorSettings();
return colors->GetColor( GetColorLayer() );
}
void PCB_MARKER::SetZoom( double aZoomFactor )
{
SetMarkerScale( SCALING_FACTOR * aZoomFactor );
}
const BOX2I PCB_MARKER::GetBoundingBox() const
{
BOX2I box = GetBoundingBoxMarker();
for( auto& s : m_shapes1 )
box.Merge( s.GetBoundingBox() );
return box;
}
const BOX2I PCB_MARKER::ViewBBox() const
{
return GetBoundingBox();
}
static struct PCB_MARKER_DESC
{
PCB_MARKER_DESC()
{
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
REGISTER_TYPE( PCB_MARKER );
propMgr.AddTypeCast( new TYPE_CAST<PCB_MARKER, BOARD_ITEM> );
propMgr.AddTypeCast( new TYPE_CAST<PCB_MARKER, MARKER_BASE> );
propMgr.InheritsAfter( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ) );
propMgr.InheritsAfter( TYPE_HASH( PCB_MARKER ), TYPE_HASH( MARKER_BASE ) );
// Markers cannot be locked and have no user-accessible layer control
propMgr.OverrideAvailability( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ),
_HKI( "Layer" ),
[]( INSPECTABLE* aItem ) { return false; } );
propMgr.OverrideAvailability( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ),
_HKI( "Locked" ),
[]( INSPECTABLE* aItem ) { return false; } );
}
} _PCB_MARKER_DESC;