diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 452c0027e3..96290714c0 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -861,6 +861,8 @@ set( PCB_COMMON_SRCS ${CMAKE_SOURCE_DIR}/pcbnew/tools/pcb_editor_conditions.cpp ${CMAKE_SOURCE_DIR}/pcbnew/tools/pcb_viewer_tools.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/length_calculation.cpp + widgets/net_selector.cpp ) diff --git a/common/advanced_config.cpp b/common/advanced_config.cpp index 58448bee9f..07fa66c824 100644 --- a/common/advanced_config.cpp +++ b/common/advanced_config.cpp @@ -301,7 +301,7 @@ ADVANCED_CFG::ADVANCED_CFG() m_MinimumMarkerSeparationDistance = 0.15; - m_NetInspectorBulkUpdateOptimisationThreshold = 25; + m_NetInspectorBulkUpdateOptimisationThreshold = 100; m_ExcludeFromSimulationLineWidth = 25; diff --git a/libs/kimath/include/geometry/shape_line_chain.h b/libs/kimath/include/geometry/shape_line_chain.h index 223f44c54d..f904b51ee9 100644 --- a/libs/kimath/include/geometry/shape_line_chain.h +++ b/libs/kimath/include/geometry/shape_line_chain.h @@ -409,10 +409,7 @@ public: return m_points[aIndex]; } - const std::vector& CPoints() const - { - return m_points; - } + const std::vector& CPoints() const { return m_points; } /** * Return the last point in the line chain. diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index 4bdf36175f..4b8a59d525 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -75,12 +75,11 @@ VECTOR2I BOARD_ITEM::ZeroOffset( 0, 0 ); BOARD::BOARD() : BOARD_ITEM_CONTAINER( (BOARD_ITEM*) nullptr, PCB_T ), m_LegacyDesignSettingsLoaded( false ), - m_LegacyCopperEdgeClearanceLoaded( false ), m_LegacyNetclassesLoaded( false ), - m_boardUse( BOARD_USE::NORMAL ), m_timeStamp( 1 ), m_paper( PAGE_INFO::A4 ), - m_project( nullptr ), m_userUnits( EDA_UNITS::MM ), - m_designSettings( new BOARD_DESIGN_SETTINGS( nullptr, "board.design_settings" ) ), - m_NetInfo( this ), m_embedFonts( false ), - m_componentClassManager( std::make_unique( this ) ) + m_LegacyCopperEdgeClearanceLoaded( false ), m_LegacyNetclassesLoaded( false ), m_boardUse( BOARD_USE::NORMAL ), + m_timeStamp( 1 ), m_paper( PAGE_INFO::A4 ), m_project( nullptr ), m_userUnits( EDA_UNITS::MM ), + m_designSettings( new BOARD_DESIGN_SETTINGS( nullptr, "board.design_settings" ) ), m_NetInfo( this ), + m_embedFonts( false ), m_componentClassManager( std::make_unique( this ) ), + m_lengthCalc( std::make_unique( this ) ) { // A too small value do not allow connecting 2 shapes (i.e. segments) not exactly connected // A too large value do not allow safely connecting 2 shapes like very short segments. @@ -2399,82 +2398,24 @@ BOARD_STACKUP BOARD::GetStackupOrDefault() const std::tuple BOARD::GetTrackLength( const PCB_TRACK& aTrack ) const { - int count = 0; - double length = 0.0; - double package_length = 0.0; + auto connectivity = GetBoard()->GetConnectivity(); - auto connectivity = GetBoard()->GetConnectivity(); - BOARD_STACKUP& stackup = GetDesignSettings().GetStackupDescriptor(); - bool useHeight = GetDesignSettings().m_UseHeightForLengthCalcs; + std::vector items; - for( BOARD_CONNECTED_ITEM* item : connectivity->GetConnectedItems( &aTrack, EXCLUDE_ZONES ) ) + for( BOARD_CONNECTED_ITEM* boardItem : connectivity->GetConnectedItems( &aTrack, EXCLUDE_ZONES ) ) { - count++; + LENGTH_CALCULATION_ITEM item = GetLengthCalculation()->GetLengthCalculationItem( boardItem ); - if( PCB_TRACK* track = dynamic_cast( item ) ) - { - if( track->Type() == PCB_VIA_T && useHeight ) - { - PCB_VIA* via = static_cast( track ); - length += stackup.GetLayerDistance( via->TopLayer(), via->BottomLayer() ); - continue; - } - else if( track->Type() == PCB_ARC_T ) - { - // Note: we don't apply the clip-to-pad optimization if an arc ends in a pad - // Room for future improvement. - length += track->GetLength(); - continue; - } - - bool inPad = false; - SEG trackSeg( track->GetStart(), track->GetEnd() ); - double segLen = trackSeg.Length(); - double segInPadLen = 0; - - for( auto pad_it : connectivity->GetConnectedPads( item ) ) - { - PAD* pad = static_cast( pad_it ); - - bool hitStart = pad->HitTest( track->GetStart(), track->GetWidth() / 2 ); - bool hitEnd = pad->HitTest( track->GetEnd(), track->GetWidth() / 2 ); - - if( hitStart && hitEnd ) - { - inPad = true; - break; - } - else if( hitStart || hitEnd ) - { - VECTOR2I loc; - - // We may not collide even if we passed the bounding-box hit test - if( pad->GetEffectivePolygon( track->GetLayer(), ERROR_INSIDE )->Collide( trackSeg, 0, nullptr, &loc ) ) - { - // Part 1: length of the seg to the intersection with the pad poly - if( hitStart ) - trackSeg.A = loc; - else - trackSeg.B = loc; - - segLen = trackSeg.Length(); - - // Part 2: length from the intersection to the pad anchor - segInPadLen += ( loc - pad->GetPosition() ).EuclideanNorm(); - } - } - } - - if( !inPad ) - length += segLen + segInPadLen; - } - else if( PAD* pad = dynamic_cast( item ) ) - { - package_length += pad->GetPadToDieLength(); - } + if( item.Type() != LENGTH_CALCULATION_ITEM::TYPE::UNKNOWN ) + items.push_back( item ); } - return std::make_tuple( count, length, package_length ); + constexpr PATH_OPTIMISATIONS opts = { + .OptimiseViaLayers = true, .MergeTracks = true, .OptimiseTracesInPads = true, .InferViaInPad = false + }; + LENGTH_DETAILS details = GetLengthCalculation()->CalculateLengthDetails( items, opts ); + + return std::make_tuple( items.size(), details.TrackLength + details.ViaLength, details.PadToDieLength ); } diff --git a/pcbnew/board.h b/pcbnew/board.h index b610934df2..9dd69543ba 100644 --- a/pcbnew/board.h +++ b/pcbnew/board.h @@ -33,6 +33,7 @@ #include // for OUTLINE_ERROR_HANDLER #include #include +#include #include #include #include @@ -1304,6 +1305,11 @@ public: */ void EmbedFonts() override; + /** + * Returns the track length calculator + */ + LENGTH_CALCULATION* GetLengthCalculation() const { return m_lengthCalc.get(); } + /** * Gets the component class manager */ @@ -1428,6 +1434,8 @@ private: bool m_embedFonts; std::unique_ptr m_componentClassManager; + + std::unique_ptr m_lengthCalc; }; diff --git a/pcbnew/drc/drc_test_provider_matched_length.cpp b/pcbnew/drc/drc_test_provider_matched_length.cpp index 6b583a3fa6..f3ed3b4069 100644 --- a/pcbnew/drc/drc_test_provider_matched_length.cpp +++ b/pcbnew/drc/drc_test_provider_matched_length.cpp @@ -345,20 +345,25 @@ bool DRC_TEST_PROVIDER_MATCHED_LENGTH::runInternal( bool aDelayReportMode ) return true; } ); + LENGTH_CALCULATION* calc = m_board->GetLengthCalculation(); + std::map< DRC_RULE*, std::vector > matches; - for( const std::pair< DRC_RULE* const, std::set >& it : itemSets ) + for( const auto& [rule, ruleItems] : itemSets ) { std::map > netMap; - for( BOARD_CONNECTED_ITEM* citem : it.second ) - netMap[ citem->GetNetCode() ].insert( citem ); + for( BOARD_CONNECTED_ITEM* item : ruleItems ) + netMap[item->GetNetCode()].insert( item ); - for( const std::pair< const int, std::set >& nitem : netMap ) + for( const auto& [netCode, netItems] : netMap ) { + std::vector lengthItems; + lengthItems.reserve( netItems.size() ); + CONNECTION ent; - ent.items = nitem.second; - ent.netcode = nitem.first; + ent.items = netItems; + ent.netcode = netCode; ent.netname = m_board->GetNetInfo().GetNetItem( ent.netcode )->GetNetname(); ent.netinfo = m_board->GetNetInfo().GetNetItem( ent.netcode ); @@ -369,43 +374,24 @@ bool DRC_TEST_PROVIDER_MATCHED_LENGTH::runInternal( bool aDelayReportMode ) ent.fromItem = nullptr; ent.toItem = nullptr; - for( BOARD_CONNECTED_ITEM* citem : nitem.second ) + for( BOARD_CONNECTED_ITEM* item : netItems ) { - if( citem->Type() == PCB_VIA_T ) - { - const BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); - const BOARD_STACKUP& stackup = bds.GetStackupDescriptor(); - - ent.viaCount++; + LENGTH_CALCULATION_ITEM lengthItem = calc->GetLengthCalculationItem( item ); - if( bds.m_UseHeightForLengthCalcs ) - { - const PCB_VIA* v = static_cast( citem ); - PCB_LAYER_ID topmost; - PCB_LAYER_ID bottommost; - - v->GetOutermostConnectedLayers( &topmost, &bottommost ); - - if( topmost != UNDEFINED_LAYER && topmost != bottommost ) - ent.totalVia += stackup.GetLayerDistance( topmost, bottommost ); - } - } - else if( citem->Type() == PCB_TRACE_T ) - { - ent.totalRoute += static_cast( citem )->GetLength(); - } - else if ( citem->Type() == PCB_ARC_T ) - { - ent.totalRoute += static_cast( citem )->GetLength(); - } - else if( citem->Type() == PCB_PAD_T ) - { - ent.totalPadToDie += static_cast( citem )->GetPadToDieLength(); - } + if( lengthItem.Type() != LENGTH_CALCULATION_ITEM::TYPE::UNKNOWN ) + lengthItems.emplace_back( lengthItem ); } + constexpr PATH_OPTIMISATIONS opts = { + .OptimiseViaLayers = true, .MergeTracks = true, .OptimiseTracesInPads = true, .InferViaInPad = false + }; + LENGTH_DETAILS details = calc->CalculateLengthDetails( lengthItems, opts ); + ent.viaCount = details.NumVias; + ent.totalVia = details.ViaLength; + ent.totalRoute = static_cast( details.TrackLength ); + ent.totalPadToDie = details.PadToDieLength; ent.total = ent.totalRoute + ent.totalVia + ent.totalPadToDie; - ent.matchingRule = it.first; + ent.matchingRule = rule; // fixme: doesn't seem to work ;-) auto ftPath = ftCache->QueryFromToPath( ent.items ); @@ -421,7 +407,7 @@ bool DRC_TEST_PROVIDER_MATCHED_LENGTH::runInternal( bool aDelayReportMode ) } m_report.Add( ent ); - matches[ it.first ].push_back(ent); + matches[rule].push_back( ent ); } } @@ -452,19 +438,14 @@ bool DRC_TEST_PROVIDER_MATCHED_LENGTH::runInternal( bool aDelayReportMode ) for( const DRC_LENGTH_REPORT::ENTRY& ent : matchedConnections ) { - reportAux(wxString::Format( wxT( " - net: %s, from: %s, to: %s, " - "%d matching items, " - "total: %s (tracks: %s, vias: %s, pad-to-die: %s), " - "vias: %d" ), - ent.netname, - ent.from, - ent.to, - (int) ent.items.size(), - MessageTextFromValue( ent.total ), - MessageTextFromValue( ent.totalRoute ), - MessageTextFromValue( ent.totalVia ), - MessageTextFromValue( ent.totalPadToDie ), - ent.viaCount ) ); + reportAux( wxString::Format( wxT( " - net: %s, from: %s, to: %s, " + "%d matching items, " + "total: %s (tracks: %s, vias: %s, pad-to-die: %s), " + "vias: %d" ), + ent.netname, ent.from, ent.to, static_cast( ent.items.size() ), + MessageTextFromValue( ent.total ), MessageTextFromValue( ent.totalRoute ), + MessageTextFromValue( ent.totalVia ), + MessageTextFromValue( ent.totalPadToDie ), ent.viaCount ) ); } diff --git a/pcbnew/length_calculation.cpp b/pcbnew/length_calculation.cpp new file mode 100644 index 0000000000..6051f5bfb4 --- /dev/null +++ b/pcbnew/length_calculation.cpp @@ -0,0 +1,556 @@ +/* +* This program source code file is part of KiCad, a free EDA CAD application. + * + * 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 + +#include +#include +#include + + +void LENGTH_CALCULATION_ITEM::CalculateViaLayers( const BOARD* aBoard ) +{ + static std::initializer_list traceAndPadTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T }; + + PCB_LAYER_ID top_layer = UNDEFINED_LAYER; + PCB_LAYER_ID bottom_layer = UNDEFINED_LAYER; + + const LSET layers = aBoard->GetDesignSettings().GetEnabledLayers(); + + for( auto layer_it = layers.copper_layers_begin(); layer_it != layers.copper_layers_end(); ++layer_it ) + { + if( aBoard->GetConnectivity()->IsConnectedOnLayer( m_via, *layer_it, traceAndPadTypes ) ) + { + if( top_layer == UNDEFINED_LAYER ) + top_layer = *layer_it; + else + bottom_layer = *layer_it; + } + } + + if( top_layer == UNDEFINED_LAYER ) + top_layer = m_via->TopLayer(); + if( bottom_layer == UNDEFINED_LAYER ) + bottom_layer = m_via->BottomLayer(); + + SetLayers( bottom_layer, top_layer ); +} + + +void LENGTH_CALCULATION::clipLineToPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aLayer, bool aForward ) +{ + const int start = aForward ? 0 : aLine.PointCount() - 1; + const int delta = aForward ? 1 : -1; + + // Note: we don't apply the clip-to-pad optimization if an arc ends in a pad + // Room for future improvement. + if( aLine.IsPtOnArc( start ) ) + return; + + const auto& shape = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE ); + + // Skip the "first" (or last) vertex, we already know it's contained in the pad + int clip = start; + + for( int vertex = start + delta; aForward ? vertex < aLine.PointCount() : vertex >= 0; vertex += delta ) + { + SEG seg( aLine.GetPoint( vertex ), aLine.GetPoint( vertex - delta ) ); + + bool containsA = shape->Contains( seg.A ); + bool containsB = shape->Contains( seg.B ); + + if( containsA && containsB ) + { + // Whole segment is inside: clip out this segment + clip = vertex; + } + else if( containsB ) + { + // Only one point inside: Find the intersection + VECTOR2I loc; + + if( shape->Collide( seg, 0, nullptr, &loc ) ) + { + aLine.Replace( vertex - delta, vertex - delta, loc ); + } + } + } + + if( !aForward && clip < start ) + aLine.Remove( clip + 1, start ); + else if( clip > start ) + aLine.Remove( start, clip - 1 ); + + // Now connect the dots + aLine.Insert( aForward ? 0 : aLine.PointCount(), aPad->GetPosition() ); +} + + +LENGTH_DETAILS LENGTH_CALCULATION::CalculateLengthDetails( std::vector& aItems, + const PATH_OPTIMISATIONS aOptimisations, + const PAD* aStartPad, const PAD* aEndPad, + const bool aWithLayerLengths ) const +{ + // If this set of items has not been optimised, optimise for shortest electrical path + if( aOptimisations.OptimiseViaLayers || aOptimisations.MergeTracks || aOptimisations.MergeTracks ) + { + std::vector pads; + std::vector lines; + std::vector vias; + + // Map of line endpoints to line objects + std::map> linesPositionMap; + + // Map of pad positions to pad objects + std::map> padsPositionMap; + + for( LENGTH_CALCULATION_ITEM& item : aItems ) + { + if( item.Type() == LENGTH_CALCULATION_ITEM::TYPE::PAD ) + { + pads.emplace_back( &item ); + padsPositionMap[item.GetPad()->GetPosition()].insert( &item ); + } + else if( item.Type() == LENGTH_CALCULATION_ITEM::TYPE::VIA ) + { + vias.emplace_back( &item ); + } + else if( item.Type() == LENGTH_CALCULATION_ITEM::TYPE::LINE ) + { + lines.emplace_back( &item ); + linesPositionMap[item.GetLine().CPoint( 0 )].insert( &item ); + linesPositionMap[item.GetLine().CLastPoint()].insert( &item ); + } + } + + if( aOptimisations.OptimiseViaLayers ) + optimiseViaLayers( vias, lines, linesPositionMap, padsPositionMap ); + + if( aOptimisations.MergeTracks ) + mergeLines( lines, linesPositionMap ); + + if( aOptimisations.OptimiseTracesInPads ) + optimiseTracesInPads( pads, lines ); + } + + LENGTH_DETAILS details; + + if( aWithLayerLengths ) + details.LayerLengths = std::make_unique>(); + + const bool useHeight = m_board->GetDesignSettings().m_UseHeightForLengthCalcs; + + // If this is a contiguous set of items, check if we have an inferred fanout via at either end. Note that this + // condition only arises as a result of how PNS assembles tuning paths - for DRC / net inspector calculations these + // fanout vias will be present in the object set and therefore do not need to be inferred + if( aOptimisations.InferViaInPad && useHeight ) + { + inferViaInPad( aStartPad, aItems.front(), details ); + inferViaInPad( aEndPad, aItems.back(), details ); + } + + // Add stats for each item + for( const LENGTH_CALCULATION_ITEM& item : aItems ) + { + // Don't include merged items + if( item.GetMergeStatus() == LENGTH_CALCULATION_ITEM::MERGE_STATUS::MERGED_RETIRED + || item.Type() == LENGTH_CALCULATION_ITEM::TYPE::UNKNOWN ) + { + continue; + } + + if( item.Type() == LENGTH_CALCULATION_ITEM::TYPE::LINE ) + { + const int64_t length = item.GetLine().Length(); + + details.TrackLength += length; + + if( details.LayerLengths ) + ( *details.LayerLengths )[item.GetStartLayer()] += length; + } + else if( item.Type() == LENGTH_CALCULATION_ITEM::TYPE::VIA && useHeight ) + { + const auto [layerStart, layerEnd] = item.GetLayers(); + details.ViaLength += stackupHeight( layerStart, layerEnd ); + details.NumVias += 1; + } + else if( item.Type() == LENGTH_CALCULATION_ITEM::TYPE::PAD ) + { + details.PadToDieLength += item.GetPad()->GetPadToDieLength(); + details.NumPads += 1; + } + } + + return details; +} + + +void LENGTH_CALCULATION::inferViaInPad( const PAD* aPad, const LENGTH_CALCULATION_ITEM& aItem, + LENGTH_DETAILS& aDetails ) const +{ + if( aPad && aItem.Type() == LENGTH_CALCULATION_ITEM::TYPE::LINE ) + { + const PCB_LAYER_ID startBottomLayer = aItem.GetStartLayer(); + const LSET padLayers = aPad->Padstack().LayerSet(); + + if( !padLayers.Contains( startBottomLayer ) ) + { + // This must be either F_Cu or B_Cu + const PCB_LAYER_ID padLayer = padLayers.Contains( F_Cu ) ? F_Cu : B_Cu; + + aDetails.NumVias += 1; + aDetails.ViaLength += stackupHeight( startBottomLayer, padLayer ); + } + } +} + + +int64_t LENGTH_CALCULATION::CalculateLength( std::vector& aItems, + const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad, + const PAD* aEndPad ) const +{ + return CalculateLengthDetails( aItems, aOptimisations, aStartPad, aEndPad ).TotalLength(); +} + + +int LENGTH_CALCULATION::stackupHeight( const PCB_LAYER_ID aFirstLayer, const PCB_LAYER_ID aSecondLayer ) const +{ + if( !m_board || !m_board->GetDesignSettings().m_UseHeightForLengthCalcs ) + return 0; + + if( m_board->GetDesignSettings().m_HasStackup ) + { + const BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor(); + return stackup.GetLayerDistance( aFirstLayer, aSecondLayer ); + } + else + { + BOARD_STACKUP stackup; + stackup.BuildDefaultStackupList( &m_board->GetDesignSettings(), m_board->GetCopperLayerCount() ); + return stackup.GetLayerDistance( aFirstLayer, aSecondLayer ); + } +} + + +void LENGTH_CALCULATION::mergeLines( + std::vector& aLines, + std::map>& aLinesPositionMap ) +{ + // Vector of pads, and an associated flag to indicate whether they have been visited by the clustering algorithm + std::vector pads; + + auto removeFromPositionMap = [&aLinesPositionMap]( LENGTH_CALCULATION_ITEM* line ) + { + aLinesPositionMap[line->GetLine().CPoint( 0 )].erase( line ); + aLinesPositionMap[line->GetLine().CLastPoint()].erase( line ); + }; + + // Attempts to merge unmerged lines in to aPrimaryLine + auto tryMerge = [&removeFromPositionMap, &aLinesPositionMap]( const MERGE_POINT aMergePoint, + const VECTOR2I& aMergePos, + const LENGTH_CALCULATION_ITEM* aPrimaryItem, + SHAPE_LINE_CHAIN& aPrimaryLine, bool* aDidMerge ) + { + const auto startItr = aLinesPositionMap.find( aMergePos ); + + if( startItr == aLinesPositionMap.end() ) + return; + + std::unordered_set& startItems = startItr->second; + + if( startItems.size() != 1 ) + return; + + LENGTH_CALCULATION_ITEM* lineToMerge = *startItems.begin(); + + // Don't merge if line is an arc + if( !lineToMerge->GetLine().CArcs().empty() ) + return; + + // Don't merge if lines are on different layers + if( aPrimaryItem->GetStartLayer() != lineToMerge->GetStartLayer() ) + return; + + // Merge the lines + lineToMerge->SetMergeStatus( LENGTH_CALCULATION_ITEM::MERGE_STATUS::MERGED_RETIRED ); + mergeShapeLineChains( aPrimaryLine, lineToMerge->GetLine(), aMergePoint ); + removeFromPositionMap( lineToMerge ); + *aDidMerge = true; + }; + + // Cluster all lines in to contiguous entities + for( LENGTH_CALCULATION_ITEM* primaryItem : aLines ) + { + // Don't start with an already merged line + if( primaryItem->GetMergeStatus() != LENGTH_CALCULATION_ITEM::MERGE_STATUS::UNMERGED ) + continue; + + // Remove starting line from the position map + removeFromPositionMap( primaryItem ); + + SHAPE_LINE_CHAIN& primaryLine = primaryItem->GetLine(); + + // Merge all endpoints + primaryItem->SetMergeStatus( LENGTH_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE ); + bool mergeComplete = false; + + while( !mergeComplete ) + { + bool startMerged = false; + bool endMerged = false; + + VECTOR2I startPos = primaryLine.CPoint( 0 ); + VECTOR2I endPos = primaryLine.CLastPoint(); + + tryMerge( MERGE_POINT::START, startPos, primaryItem, primaryLine, &startMerged ); + tryMerge( MERGE_POINT::END, endPos, primaryItem, primaryLine, &endMerged ); + + mergeComplete = !startMerged && !endMerged; + } + } +} + + +void LENGTH_CALCULATION::mergeShapeLineChains( SHAPE_LINE_CHAIN& aPrimary, const SHAPE_LINE_CHAIN& aSecondary, + const MERGE_POINT aMergePoint ) +{ + if( aMergePoint == MERGE_POINT::START ) + { + if( aSecondary.GetPoint( 0 ) == aPrimary.GetPoint( 0 ) ) + { + for( auto itr = aSecondary.CPoints().begin() + 1; itr != aSecondary.CPoints().end(); ++itr ) + aPrimary.Insert( 0, *itr ); + } + else + { + wxASSERT( aSecondary.CLastPoint() == aPrimary.GetPoint( 0 ) ); + + for( auto itr = aSecondary.CPoints().rbegin() + 1; itr != aSecondary.CPoints().rend(); ++itr ) + aPrimary.Insert( 0, *itr ); + } + } + else + { + if( aSecondary.GetPoint( 0 ) == aPrimary.CLastPoint() ) + { + for( auto itr = aSecondary.CPoints().begin() + 1; itr != aSecondary.CPoints().end(); ++itr ) + aPrimary.Append( *itr ); + } + else + { + wxASSERT( aSecondary.CLastPoint() == aPrimary.CLastPoint() ); + + for( auto itr = aSecondary.CPoints().rbegin() + 1; itr != aSecondary.CPoints().rend(); ++itr ) + aPrimary.Append( *itr ); + } + } +} + + +void LENGTH_CALCULATION::optimiseTracesInPads( const std::vector& aPads, + const std::vector& aLines ) +{ + for( LENGTH_CALCULATION_ITEM* padItem : aPads ) + { + PAD* pad = padItem->GetPad(); + + for( LENGTH_CALCULATION_ITEM* lineItem : aLines ) + { + // Ignore merged lines + if( lineItem->GetMergeStatus() != LENGTH_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE ) + continue; + + const PCB_LAYER_ID pcbLayer = lineItem->GetStartLayer(); + SHAPE_LINE_CHAIN& line = lineItem->GetLine(); + + OptimiseTraceInPad( line, pad, pcbLayer ); + } + } +} + + +void LENGTH_CALCULATION::optimiseViaLayers( + const std::vector& aVias, std::vector& aLines, + std::map>& aLinesPositionMap, + const std::map>& aPadsPositionMap ) +{ + for( LENGTH_CALCULATION_ITEM* via : aVias ) + { + auto lineItr = aLinesPositionMap.find( via->GetVia()->GetPosition() ); + + if( lineItr == aLinesPositionMap.end() ) + continue; + + std::unordered_set& connectedLines = lineItr->second; + + if( connectedLines.empty() ) + { + // No connected lines - this via is floating. Set both layers to the same + via->SetLayers( via->GetVia()->GetLayer(), via->GetVia()->GetLayer() ); + } + else if( connectedLines.size() == 1 ) + { + // This is either a via stub, or a via-in-pad + bool isViaInPad = false; + const PCB_LAYER_ID lineLayer = ( *connectedLines.begin() )->GetStartLayer(); + + auto padItr = aPadsPositionMap.find( via->GetVia()->GetPosition() ); + + if( padItr != aLinesPositionMap.end() ) + { + // This could be a via-in-pad - check for overlapping pads which are not on the line layer + const std::unordered_set& pads = padItr->second; + + if( pads.size() == 1 ) + { + const LENGTH_CALCULATION_ITEM* padItem = *pads.begin(); + + if( !padItem->GetPad()->Padstack().LayerSet().Contains( lineLayer ) ) + { + // This is probably a via-in-pad + isViaInPad = true; + via->SetLayers( lineLayer, padItem->GetStartLayer() ); + } + } + } + + if( !isViaInPad ) + { + // This is a via stub - make its electrical length 0 + via->SetLayers( lineLayer, lineLayer ); + } + } + else + { + // This via has more than one track ending at it. Calculate the connected layer span (which may be shorter + // than the overall via span) + LSET layers; + + for( const LENGTH_CALCULATION_ITEM* lineItem : connectedLines ) + layers.set( lineItem->GetStartLayer() ); + + LSEQ cuStack = layers.CuStack(); + + PCB_LAYER_ID firstLayer = UNDEFINED_LAYER; + PCB_LAYER_ID lastLayer = UNDEFINED_LAYER; + + for( PCB_LAYER_ID layer : cuStack ) + { + if( firstLayer == UNDEFINED_LAYER ) + firstLayer = layer; + else + lastLayer = layer; + } + + if( lastLayer == UNDEFINED_LAYER ) + via->SetLayers( firstLayer, firstLayer ); + else + via->SetLayers( firstLayer, lastLayer ); + } + } +} + + +void LENGTH_CALCULATION::OptimiseTraceInPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, const PCB_LAYER_ID aPcbLayer ) +{ + // Only consider lines which terminate in the pad + if( aLine.CPoint( 0 ) != aPad->GetPosition() && aLine.CLastPoint() != aPad->GetPosition() ) + return; + + if( !aPad->FlashLayer( aPcbLayer ) ) + return; + + const auto& shape = aPad->GetEffectivePolygon( aPcbLayer, ERROR_INSIDE ); + + if( shape->Contains( aLine.CPoint( 0 ) ) ) + clipLineToPad( aLine, aPad, aPcbLayer, true ); + else if( shape->Contains( aLine.CPoint( -1 ) ) ) + clipLineToPad( aLine, aPad, aPcbLayer, false ); +} + + +LENGTH_CALCULATION_ITEM LENGTH_CALCULATION::GetLengthCalculationItem( BOARD_CONNECTED_ITEM* aBoardItem ) const +{ + if( PCB_TRACK* track = dynamic_cast( aBoardItem ) ) + { + if( track->Type() == PCB_VIA_T ) + { + PCB_VIA* via = static_cast( track ); + + LENGTH_CALCULATION_ITEM item; + item.SetVia( via ); + item.CalculateViaLayers( m_board ); + + return item; + } + + if( track->Type() == PCB_ARC_T ) + { + PCB_ARC* arcParent = static_cast( track ); + SHAPE_ARC shapeArc( arcParent->GetStart(), arcParent->GetMid(), arcParent->GetEnd(), + arcParent->GetWidth() ); + SHAPE_LINE_CHAIN chainArc( shapeArc ); + + LENGTH_CALCULATION_ITEM item; + item.SetLine( chainArc ); + item.SetLayers( track->GetLayer() ); + + return item; + } + + if( track->Type() == PCB_TRACE_T ) + { + std::vector points{ track->GetStart(), track->GetEnd() }; + SHAPE_LINE_CHAIN shape( points ); + + LENGTH_CALCULATION_ITEM item; + item.SetLine( shape ); + item.SetLayers( track->GetLayer() ); + + return item; + } + } + else if( PAD* pad = dynamic_cast( aBoardItem ) ) + { + LENGTH_CALCULATION_ITEM item; + item.SetPad( pad ); + + LSET& layers = pad->Padstack().LayerSet(); + PCB_LAYER_ID firstLayer = UNDEFINED_LAYER; + PCB_LAYER_ID secondLayer = UNDEFINED_LAYER; + + for( auto itr = layers.copper_layers_begin(); itr != layers.copper_layers_end(); ++itr ) + { + if( firstLayer == UNDEFINED_LAYER ) + firstLayer = *itr; + else + secondLayer = *itr; + } + + item.SetLayers( firstLayer, secondLayer ); + + return item; + } + + return {}; +} diff --git a/pcbnew/length_calculation.h b/pcbnew/length_calculation.h new file mode 100644 index 0000000000..619e6e1498 --- /dev/null +++ b/pcbnew/length_calculation.h @@ -0,0 +1,288 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * 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 + */ + +#ifndef PCBNEW_LENGTH_CALCULATION_H +#define PCBNEW_LENGTH_CALCULATION_H + +#include +#include +#include +#include +#include +#include +#include + +class BOARD; + +/** + * Lightweight class which holds a pad, via, or a routed trace outline. Proxied objects passed by pointer are not + * owned by this container. + */ +class LENGTH_CALCULATION_ITEM +{ +public: + /// The type of routing object this item proxies + enum class TYPE + { + UNKNOWN, + PAD, + LINE, + VIA + }; + + /// Whether this item is UNMERGED, it has been merged and should be used (MERGED_IN_USE), or it has been merged + /// and has been retired from use (MERGED_RETIRED). MERGED_RETIRED essentially means the object has been merged + /// in to a MERGED_IN_USE item. + enum class MERGE_STATUS + { + UNMERGED, + MERGED_IN_USE, + MERGED_RETIRED + }; + + /// Gets the routing item type + TYPE Type() const { return m_type; }; + + /// Sets the parent PAD associated with this item + void SetPad( PAD* aPad ) + { + m_type = TYPE::PAD; + m_pad = aPad; + } + + /// Gets the parent PAD associated with this item + PAD* GetPad() const { return m_pad; } + + /// Sets the source SHAPE_LINE_CHAIN of this item + void SetLine( const SHAPE_LINE_CHAIN& aLine ) + { + m_type = TYPE::LINE; + m_line = aLine; + } + + /// Gets the SHAPE_LINE_CHAIN associated with this item + SHAPE_LINE_CHAIN& GetLine() const { return m_line; } + + /// Sets the VIA associated with this item + void SetVia( PCB_VIA* aVia ) + { + m_type = TYPE::VIA; + m_via = aVia; + } + + /// Gets the VIA associated with this item + PCB_VIA* GetVia() const { return m_via; } + + /// Sets the first and last layers associated with this item + void SetLayers( const PCB_LAYER_ID aStart, const PCB_LAYER_ID aEnd = PCB_LAYER_ID::UNDEFINED_LAYER ) + { + m_layerStart = aStart; + m_layerEnd = aEnd; + } + + /// Sets the MERGE_STATUS of this item. MERGED_RETIRED essentially means the object has been merged + /// in to a MERGED_IN_USE item. + void SetMergeStatus( const MERGE_STATUS aStatus ) { m_mergeStatus = aStatus; } + + /// Gets the MERGE_STATUS of this item + MERGE_STATUS GetMergeStatus() const { return m_mergeStatus; } + + /// Gets the upper and lower layers for the proxied item + std::tuple GetLayers() const { return { m_layerStart, m_layerEnd }; } + + /// Gets the start board layer for the proxied item + PCB_LAYER_ID GetStartLayer() const { return m_layerStart; } + + /// Gets the end board layer for the proxied item. + PCB_LAYER_ID GetEndLayer() const { return m_layerEnd; } + + /// Calculates active via payers for a proxied VIA object + void CalculateViaLayers( const BOARD* aBoard ); + +protected: + /// A proxied PAD object. Set to nullptr if not proxying a PAD. + PAD* m_pad{ nullptr }; + + /// A proxied SHAPE_LINE_CHAIN object. Line is empty if not proxying a SHAPE_LINE_CHAIN. + mutable SHAPE_LINE_CHAIN m_line; + + /// A proxied PVIAAD object. Set to nullptr if not proxying a VIA. + PCB_VIA* m_via{ nullptr }; + + /// The start board layer for the proxied object + PCB_LAYER_ID m_layerStart{ PCB_LAYER_ID::UNDEFINED_LAYER }; + + /// The end board layer for the proxied object + PCB_LAYER_ID m_layerEnd{ PCB_LAYER_ID::UNDEFINED_LAYER }; + + /// Flags whether this item has already been merged with another + MERGE_STATUS m_mergeStatus{ MERGE_STATUS::UNMERGED }; + + /// The routing object type of the proxied parent + TYPE m_type{ TYPE::UNKNOWN }; +}; + + +/** +* Holds length measurement result details and statistics +*/ +struct LENGTH_DETAILS +{ + int NumPads{ 0 }; + int NumVias{ 0 }; + int ViaLength{ 0 }; + int64_t TrackLength{ 0 }; + int PadToDieLength{ 0 }; + std::unique_ptr> LayerLengths; + + int64_t TotalLength() const { return ViaLength + TrackLength + PadToDieLength; } +}; + + +/** + * Struct to control which optimisations the length calculation code runs on + * the given path objects. This is required as some call sites (e.g. PNS) run + * their own path optimisation, whereas others (e.g. Net Inspector) do not. + */ +struct PATH_OPTIMISATIONS +{ + /// Optimise via layers for height calculations, ensuring only the distance + /// between routed segments is considered + bool OptimiseViaLayers = false; + + /// Merges all contiguous (end-to-end, same layer) tracks + bool MergeTracks = false; + + /// Optimises the electrical length of tracks within pads. Note that the track + /// must terminate at the trace anchor point to be considered for + /// optimisation. Will require MergeTracks if used with a non-contiguous item + /// set. + bool OptimiseTracesInPads = false; + + /// Determines if there is a via-in-pad present on the board but not in the + /// item set. This condition can arise from the PNS meander placer. + /// TODO (JJ): This can be fixed in the router + bool InferViaInPad = false; +}; + + +/** +* Class which calculates lengths (and associated routing statistics) in a BOARD context +*/ +class LENGTH_CALCULATION +{ +public: + /// Construct the calculator in the given BOARD context + explicit LENGTH_CALCULATION( BOARD* aBoard ) : m_board( aBoard ) {} + + /** + * @brief Calculates the electrical length of the given items + * @param aItems is the vector of items making up the route + * @param aPathType indicates whether this is an ordered route, or an unordered collection + * @param aOptimised indicates whether this has been optimised for electrical length (e.g. clipping within pads) + * @param aStartPad is the starting pad of the route + * @param aEndPad is the ending pad of the route + */ + int64_t CalculateLength( std::vector& aItems, PATH_OPTIMISATIONS aOptimisations, + const PAD* aStartPad = nullptr, const PAD* aEndPad = nullptr ) const; + + /** + * @brief Calculates the electrical length of the given items + * @param aItems is the vector of items making up the route + * @param aPathType indicates whether this is an ordered route, or an unordered collection + * @param aOptimised indicates whether this has been optimised for electrical length (e.g. clipping within pads) + * @param aStartPad is the starting pad of the route + * @param aEndPad is the ending pad of the route + * @param aWithLayerLengths indicates whether the layer length structure should be populated + */ + LENGTH_DETAILS CalculateLengthDetails( std::vector& aItems, + PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad = nullptr, + const PAD* aEndPad = nullptr, bool aWithLayerLengths = false ) const; + + /// Optimises the given trace / line to minimise the electrical path length within the given pad + static void OptimiseTraceInPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aPcbLayer ); + + /// Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM + LENGTH_CALCULATION_ITEM GetLengthCalculationItem( BOARD_CONNECTED_ITEM* aBoardItem ) const; + +protected: + /// The parent board for all items + BOARD* m_board; + + /// Enum to describe whether track merging is attempted from the start or end of a track segment + enum class MERGE_POINT + { + START, + END + }; + + /** + * Returns the stackup distance between the two given layers. + * + * Note: Can return 0 if the board design settings disallow stackup height calculations + */ + int stackupHeight( PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer ) const; + + /** + * Optimises the given set of items to minimise the electrical path length. At the moment + * only optimises lines attached to pads, future work could optimise paths through pads + * + * Assumes that any polylines are only connected at either end, and not at midpoints + */ + static void optimiseTracesInPads( const std::vector& aPads, + const std::vector& aLines ); + + /// Clips the given line to the minimal direct electrical length within the pad + static void clipLineToPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aLayer, bool aForward = true ); + + /** + * Optimises the via layers. Ensures that vias that are routed through only on one layer do not count towards total + * length calculations. + */ + static void + optimiseViaLayers( const std::vector& aVias, + std::vector& aLines, + std::map>& aLinesPositionMap, + const std::map>& aPadsPositionMap ); + + /** + * Merges any lines (traces) that are contiguous, on one layer, and with no junctions + */ + static void mergeLines( std::vector& aLines, + std::map>& aLinesPositionMap ); + + /** + * Merges two SHAPE_LINE_CHAINs where there is a shared endpoing. + * + * aSecondary is merged in to aPrimary + */ + static void mergeShapeLineChains( SHAPE_LINE_CHAIN& aPrimary, const SHAPE_LINE_CHAIN& aSecondary, + MERGE_POINT aMergePoint ); + + /** + * Infers if there is a via in the given pad. Adds via details to the length details data structure if found. + */ + void inferViaInPad( const PAD* aPad, const LENGTH_CALCULATION_ITEM& aItem, LENGTH_DETAILS& aDetails ) const; +}; + +#endif //PCBNEW_LENGTH_CALCULATION_H diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index 1b1d43eb42..34025875dd 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -2322,3 +2322,56 @@ PNS_LAYER_RANGE PNS_KICAD_IFACE_BASE::SetLayersFromPCBNew( PCB_LAYER_ID aStartLa return PNS_LAYER_RANGE( GetPNSLayerFromBoardLayer( aStartLayer ), GetPNSLayerFromBoardLayer( aEndLayer ) ); } + + +long long int PNS_KICAD_IFACE_BASE::CalculateRoutedPathLength( const PNS::ITEM_SET& aLine, const PNS::SOLID* aStartPad, + const PNS::SOLID* aEndPad ) +{ + std::vector lengthItems; + + for( int idx = 0; idx < aLine.Size(); idx++ ) + { + const PNS::ITEM* lineItem = aLine[idx]; + + if( const PNS::LINE* l = dyn_cast( lineItem ) ) + { + LENGTH_CALCULATION_ITEM item; + item.SetLine( l->CLine() ); + + const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() ); + item.SetLayers( layer ); + + lengthItems.emplace_back( std::move( item ) ); + } + else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 ) + { + const int layerPrev = aLine[idx - 1]->Layer(); + const int layerNext = aLine[idx + 1]->Layer(); + const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev ); + const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext ); + + if( layerPrev != layerNext ) + { + LENGTH_CALCULATION_ITEM item; + item.SetVia( static_cast( lineItem->GetSourceItem() ) ); + item.SetLayers( pcbLayerPrev, pcbLayerNext ); + lengthItems.emplace_back( std::move( item ) ); + } + } + } + + const PAD* startPad = nullptr; + const PAD* endPad = nullptr; + + if( aStartPad ) + startPad = static_cast( aStartPad->Parent() ); + + if( aEndPad ) + endPad = static_cast( aEndPad->Parent() ); + + constexpr PATH_OPTIMISATIONS opts = { + .OptimiseViaLayers = false, .MergeTracks = false, .OptimiseTracesInPads = false, .InferViaInPad = true + }; + const BOARD* board = GetBoard(); + return board->GetLengthCalculation()->CalculateLength( lengthItems, opts, startPad, endPad ); +} diff --git a/pcbnew/router/pns_kicad_iface.h b/pcbnew/router/pns_kicad_iface.h index 9bd90b266c..4c629bb437 100644 --- a/pcbnew/router/pns_kicad_iface.h +++ b/pcbnew/router/pns_kicad_iface.h @@ -83,6 +83,8 @@ public: void SetDebugDecorator( PNS::DEBUG_DECORATOR* aDec ); + long long int CalculateRoutedPathLength( const PNS::ITEM_SET& aLine, const PNS::SOLID* aStartPad, + const PNS::SOLID* aEndPad ) override; PCB_LAYER_ID GetBoardLayerFromPNSLayer( int aLayer ) const override; int GetPNSLayerFromBoardLayer( PCB_LAYER_ID aLayer ) const override; diff --git a/pcbnew/router/pns_meander_placer_base.cpp b/pcbnew/router/pns_meander_placer_base.cpp index 017d3f5036..9248c58b3a 100644 --- a/pcbnew/router/pns_meander_placer_base.cpp +++ b/pcbnew/router/pns_meander_placer_base.cpp @@ -321,60 +321,10 @@ VECTOR2I MEANDER_PLACER_BASE::getSnappedStartPoint( LINKED_ITEM* aStartItem, VEC long long int MEANDER_PLACER_BASE::lineLength( const ITEM_SET& aLine, const SOLID* aStartPad, const SOLID* aEndPad ) const { - long long int total = 0; - if( aLine.Empty() ) return 0; - const ITEM* start_item = aLine[0]; - const ITEM* end_item = aLine[aLine.Size() - 1]; - bool start_via = false; - bool end_via = false; - - - /** - * If there is a start pad but the pad's layers do not overlap the first track layer, then there must be a - * fanout via on the line. If there isn't, we still need to have the via back to the pad, so count the distance - * in the line tuning - */ - start_via = aStartPad && ( !aStartPad->LayersOverlap( start_item ) ); - end_via = aEndPad && ( !aEndPad->LayersOverlap( end_item ) ); - - for( int idx = 0; idx < aLine.Size(); idx++ ) - { - const ITEM* item = aLine[idx]; - - if( const LINE* l = dyn_cast( item ) ) - { - total += l->CLine().Length(); - } - else if( item->OfKind( ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 ) - { - int layerPrev = aLine[idx - 1]->Layer(); - int layerNext = aLine[idx + 1]->Layer(); - - if( layerPrev != layerNext ) - total += m_router->GetInterface()->StackupHeight( layerPrev, layerNext ); - } - } - - if( start_via ) - { - int layerPrev = aStartPad->Layer(); - int layerNext = start_item->Layer(); - - total += m_router->GetInterface()->StackupHeight( layerPrev, layerNext ); - } - - if( end_via ) - { - int layerPrev = end_item->Layer(); - int layerNext = aEndPad->Layer(); - - total += m_router->GetInterface()->StackupHeight( layerPrev, layerNext ); - } - - return total; + ROUTER_IFACE* iface = Router()->GetInterface(); + return iface->CalculateRoutedPathLength( aLine, aStartPad, aEndPad ); } - } diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index 0f1f4ee3fb..dd30ae9a48 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -117,6 +117,8 @@ enum DRAG_MODE virtual RULE_RESOLVER* GetRuleResolver() = 0; virtual DEBUG_DECORATOR* GetDebugDecorator() = 0; + virtual long long int CalculateRoutedPathLength( const ITEM_SET& aLine, const SOLID* aStartPad, + const SOLID* aEndPad ) = 0; virtual PCB_LAYER_ID GetBoardLayerFromPNSLayer( int aLayer ) const = 0; virtual int GetPNSLayerFromBoardLayer( PCB_LAYER_ID aLayer ) const = 0; }; diff --git a/pcbnew/router/pns_solid.h b/pcbnew/router/pns_solid.h index 04b2717fd8..67d2f6c6db 100644 --- a/pcbnew/router/pns_solid.h +++ b/pcbnew/router/pns_solid.h @@ -29,6 +29,7 @@ #include #include "pns_item.h" +#include "pns_hole.h" namespace PNS { diff --git a/pcbnew/router/pns_topology.cpp b/pcbnew/router/pns_topology.cpp index 2720a5ef84..c75fa3c9fd 100644 --- a/pcbnew/router/pns_topology.cpp +++ b/pcbnew/router/pns_topology.cpp @@ -371,53 +371,7 @@ const ITEM_SET TOPOLOGY::AssembleTuningPath( ROUTER_IFACE* aRouterIface, ITEM* a if( !padA && !padB ) return initialPath; - auto clipLineToPad = - []( SHAPE_LINE_CHAIN& aLine, PAD* aPad, PCB_LAYER_ID aLayer, bool aForward = true ) - { - const auto& shape = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE ); - - int start = aForward ? 0 : aLine.PointCount() - 1; - int delta = aForward ? 1 : -1; - - // Skip the "first" (or last) vertex, we already know it's contained in the pad - int clip = start; - - for( int vertex = start + delta; - aForward ? vertex < aLine.PointCount() : vertex >= 0; - vertex += delta ) - { - SEG seg( aLine.GetPoint( vertex ), aLine.GetPoint( vertex - delta ) ); - - bool containsA = shape->Contains( seg.A ); - bool containsB = shape->Contains( seg.B ); - - if( containsA && containsB ) - { - // Whole segment is inside: clip out this segment - clip = vertex; - } - else if( containsB ) - { - // Only one point inside: Find the intersection - VECTOR2I loc; - - if( shape->Collide( seg, 0, nullptr, &loc ) ) - { - aLine.Replace( vertex - delta, vertex - delta, loc ); - } - } - } - - if( !aForward && clip < start ) - aLine.Remove( clip + 1, start ); - else if( clip > start ) - aLine.Remove( start, clip - 1 ); - - // Now connect the dots - aLine.Insert( aForward ? 0 : aLine.PointCount(), aPad->GetPosition() ); - }; - - auto processPad = [&]( const JOINT* aJoint, PAD* aPad, int aLayer ) + auto processPad = [&]( PAD* aPad, int aLayer ) { for( int idx = 0; idx < initialPath.Size(); idx++ ) { @@ -425,32 +379,18 @@ const ITEM_SET TOPOLOGY::AssembleTuningPath( ROUTER_IFACE* aRouterIface, ITEM* a continue; LINE* line = static_cast( initialPath[idx] ); - PCB_LAYER_ID pcbLayer = aRouterIface->GetBoardLayerFromPNSLayer( line->Layer() ); - - if( !aPad->FlashLayer( pcbLayer ) ) - continue; - - const std::vector& points = line->CLine().CPoints(); - - if( points.front() != aJoint->Pos() && points.back() != aJoint->Pos() ) - continue; - - const auto& shape = aPad->GetEffectivePolygon( pcbLayer, ERROR_INSIDE ); - - SHAPE_LINE_CHAIN& slc = line->Line(); + SHAPE_LINE_CHAIN& slc = line->Line(); + const PCB_LAYER_ID pcbLayer = aRouterIface->GetBoardLayerFromPNSLayer( line->Layer() ); - if( shape->Contains( slc.CPoint( 0 ) ) ) - clipLineToPad( slc, aPad, pcbLayer, true ); - else if( shape->Contains( slc.CPoint( -1 ) ) ) - clipLineToPad( slc, aPad, pcbLayer, false ); + LENGTH_CALCULATION::OptimiseTraceInPad( slc, aPad, pcbLayer ); } }; if( padA ) - processPad( joints.first, padA, joints.first->Layer() ); + processPad( padA, joints.first->Layer() ); if( padB ) - processPad( joints.second, padB, joints.second->Layer() ); + processPad( padB, joints.second->Layer() ); return initialPath; } diff --git a/pcbnew/widgets/pcb_net_inspector_panel.cpp b/pcbnew/widgets/pcb_net_inspector_panel.cpp index eee07e24c7..9e29ec036f 100644 --- a/pcbnew/widgets/pcb_net_inspector_panel.cpp +++ b/pcbnew/widgets/pcb_net_inspector_panel.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -30,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -41,25 +39,23 @@ #include #include +#include PCB_NET_INSPECTOR_PANEL::PCB_NET_INSPECTOR_PANEL( wxWindow* parent, PCB_EDIT_FRAME* aFrame ) : - NET_INSPECTOR_PANEL( parent, aFrame ), - m_zero_netitem( nullptr ), - m_frame( aFrame ) + NET_INSPECTOR_PANEL( parent, aFrame ), m_frame( aFrame ), m_dataModel( new DATA_MODEL( *this ) ) { - m_brd = m_frame->GetBoard(); + m_board = m_frame->GetBoard(); - m_data_model = new DATA_MODEL( *this ); - m_netsList->AssociateModel( &*m_data_model ); + m_netsList->AssociateModel( &*m_dataModel ); // Rebuild nets list buildNetsList( true ); // Register the panel to receive board change notifications - if( m_brd != nullptr ) + if( m_board != nullptr ) { - OnBoardHighlightNetChanged( *m_brd ); - m_brd->AddListener( this ); + PCB_NET_INSPECTOR_PANEL::OnBoardHighlightNetChanged( *m_board ); + m_board->AddListener( this ); } // Connect to board events @@ -82,7 +78,7 @@ PCB_NET_INSPECTOR_PANEL::PCB_NET_INSPECTOR_PANEL( wxWindow* parent, PCB_EDIT_FRA PCB_NET_INSPECTOR_PANEL::~PCB_NET_INSPECTOR_PANEL() { - SaveSettings(); + PCB_NET_INSPECTOR_PANEL::SaveSettings(); m_netsList->AssociateModel( nullptr ); @@ -131,10 +127,9 @@ void PCB_NET_INSPECTOR_PANEL::buildColumns() CSV_COLUMN_DESC::CSV_NONE, true ); m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Die Length" ), _( "Die Length" ), CSV_COLUMN_DESC::CSV_NONE, true ); - m_columns.emplace_back( 7u, UNDEFINED_LAYER, _( "Pad Count" ), _( "Pad Count" ), - CSV_COLUMN_DESC::CSV_NONE, false ); + m_columns.emplace_back( 7u, UNDEFINED_LAYER, _( "Pad Count" ), _( "Pad Count" ), CSV_COLUMN_DESC::CSV_NONE, false ); - std::vector> add_col{ + const std::vector> add_col{ [&]() { m_netsList->AppendTextColumn( m_columns[COLUMN_NAME].display_name, @@ -205,7 +200,7 @@ void PCB_NET_INSPECTOR_PANEL::buildColumns() // object prior to loading the board; the two are not synced and we need to account for that) PANEL_NET_INSPECTOR_SETTINGS* cfg = nullptr; - if( m_board_loaded ) + if( m_boardLoaded ) { PROJECT_LOCAL_SETTINGS& localSettings = Pgm().GetSettingsManager().Prj().GetLocalSettings(); cfg = &localSettings.m_NetInspectorPanel; @@ -215,17 +210,8 @@ void PCB_NET_INSPECTOR_PANEL::buildColumns() cfg = new PANEL_NET_INSPECTOR_SETTINGS(); } - // Count number of copper layers - m_num_copper_layers = 0; - - for( PCB_LAYER_ID layer : m_brd->GetEnabledLayers().Seq() ) - { - if( IsCopperLayer( layer ) ) - ++m_num_copper_layers; - } - // Reset the column display settings if column count doesn't match - const int totalNumColumns = add_col.size() + m_num_copper_layers; + const int totalNumColumns = add_col.size() + m_board->GetCopperLayerCount(); if( (int) cfg->col_order.size() != totalNumColumns || (int) cfg->col_hidden.size() != totalNumColumns ) @@ -245,35 +231,34 @@ void PCB_NET_INSPECTOR_PANEL::buildColumns() if( col_order_set.size() != cfg->col_order.size() ) { for( std::size_t i = 0; i < cfg->col_order.size(); ++i ) - cfg->col_order[i] = i; + cfg->col_order[i] = static_cast( i ); } // Add column records for copper layers - for( PCB_LAYER_ID layer : m_brd->GetEnabledLayers().Seq() ) + for( PCB_LAYER_ID layer : m_board->GetEnabledLayers().Seq() ) { if( !IsCopperLayer( layer ) ) continue; - m_columns.emplace_back( m_columns.size(), layer, m_brd->GetLayerName( layer ), - m_brd->GetLayerName( layer ), CSV_COLUMN_DESC::CSV_NONE, true ); + m_columns.emplace_back( m_columns.size(), layer, m_board->GetLayerName( layer ), m_board->GetLayerName( layer ), + CSV_COLUMN_DESC::CSV_NONE, true ); } // Add display columns in settings order - for( std::size_t i = 0; i < cfg->col_order.size(); ++i ) + for( const int i : cfg->col_order ) { - const int addModelColumn = cfg->col_order[i]; + const int addModelColumn = i; if( addModelColumn >= (int) add_col.size() ) { - m_netsList->AppendTextColumn( m_brd->GetLayerName( m_columns[addModelColumn].layer ), - m_columns[addModelColumn], wxDATAVIEW_CELL_INERT, -1, - wxALIGN_CENTER, + m_netsList->AppendTextColumn( m_board->GetLayerName( m_columns[addModelColumn].layer ), + m_columns[addModelColumn], wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_SORTABLE ); } else { - add_col.at( cfg->col_order[i] )(); + add_col.at( i )(); } } @@ -286,14 +271,14 @@ void PCB_NET_INSPECTOR_PANEL::buildColumns() adjustListColumnSizes( cfg ); // Delete the temporary config if used - if( !m_board_loaded ) + if( !m_boardLoaded ) { delete cfg; } } -void PCB_NET_INSPECTOR_PANEL::adjustListColumnSizes( PANEL_NET_INSPECTOR_SETTINGS* cfg ) +void PCB_NET_INSPECTOR_PANEL::adjustListColumnSizes( PANEL_NET_INSPECTOR_SETTINGS* cfg ) const { wxWindowUpdateLocker locker( m_netsList ); @@ -307,8 +292,8 @@ void PCB_NET_INSPECTOR_PANEL::adjustListColumnSizes( PANEL_NET_INSPECTOR_SETTING // For wxRenderGeneric it is 5px. // Also account for the sorting arrow in the column header. // Column 0 also needs space for any potential expander icons. - const int margins = 15; - const int extra_width = 30; + constexpr int margins = 15; + constexpr int extra_width = 30; auto getTargetWidth = [&]( int columnID ) @@ -352,14 +337,14 @@ void PCB_NET_INSPECTOR_PANEL::adjustListColumnSizes( PANEL_NET_INSPECTOR_SETTING } -bool PCB_NET_INSPECTOR_PANEL::restoreSortColumn( int sortingColumnId, bool sortOrderAsc ) +bool PCB_NET_INSPECTOR_PANEL::restoreSortColumn( const int sortingColumnId, const bool sortOrderAsc ) const { if( sortingColumnId != -1 ) { if( wxDataViewColumn* col = getDisplayedColumnForModelField( sortingColumnId ) ) { col->SetSortOrder( sortOrderAsc ); - m_data_model->Resort(); + m_dataModel->Resort(); return true; } } @@ -368,13 +353,13 @@ bool PCB_NET_INSPECTOR_PANEL::restoreSortColumn( int sortingColumnId, bool sortO } -wxDataViewColumn* PCB_NET_INSPECTOR_PANEL::getDisplayedColumnForModelField( int columnId ) +wxDataViewColumn* PCB_NET_INSPECTOR_PANEL::getDisplayedColumnForModelField( const int columnId ) const { for( unsigned int i = 0; i < m_netsList->GetColumnCount(); ++i ) { wxDataViewColumn* col = m_netsList->GetColumn( i ); - if( (int) col->GetModelColumn() == columnId ) + if( static_cast( col->GetModelColumn() ) == columnId ) { return col; } @@ -391,26 +376,26 @@ wxDataViewColumn* PCB_NET_INSPECTOR_PANEL::getDisplayedColumnForModelField( int * ***************************************************************************************/ -void PCB_NET_INSPECTOR_PANEL::buildNetsList( bool rebuildColumns ) +void PCB_NET_INSPECTOR_PANEL::buildNetsList( const bool rebuildColumns ) { // Only build the list of nets if there is a board present - if( !m_brd ) + if( !m_board ) return; - m_in_build_nets_list = true; + m_inBuildNetsList = true; PROJECT_LOCAL_SETTINGS& localSettings = Pgm().GetSettingsManager().Prj().GetLocalSettings(); PANEL_NET_INSPECTOR_SETTINGS* cfg = &localSettings.m_NetInspectorPanel; // Refresh all filtering / grouping settings - m_filter_by_net_name = cfg->filter_by_net_name; - m_filter_by_netclass = cfg->filter_by_netclass; - m_show_zero_pad_nets = cfg->show_zero_pad_nets; - m_group_by_netclass = cfg->group_by_netclass; - m_group_by_constraint = cfg->group_by_constraint; + m_filterByNetName = cfg->filter_by_net_name; + m_filterByNetclass = cfg->filter_by_netclass; + m_showZeroPadNets = cfg->show_zero_pad_nets; + m_groupByNetclass = cfg->group_by_netclass; + m_groupByConstraint = cfg->group_by_constraint; // Attempt to keep any expanded groups open - if( m_board_loaded && !m_board_loading ) + if( m_boardLoaded && !m_boardLoading ) { cfg->expanded_rows.clear(); DATA_MODEL* model = static_cast( m_netsList->GetModel() ); @@ -423,7 +408,7 @@ void PCB_NET_INSPECTOR_PANEL::buildNetsList( bool rebuildColumns ) } } - // when rebuilding the netlist, try to keep the row selection + // When rebuilding the netlist, try to keep the row selection wxDataViewItemArray sel; m_netsList->GetSelections( sel ); @@ -441,13 +426,13 @@ void PCB_NET_INSPECTOR_PANEL::buildNetsList( bool rebuildColumns ) if( wxDataViewColumn* sorting_column = m_netsList->GetSortingColumn() ) { - if( !m_board_loading ) + if( !m_boardLoading ) { sorting_column_id = static_cast( sorting_column->GetModelColumn() ); sort_order_asc = sorting_column->IsSortOrderAscending(); } - // On GTK, wxDVC will crash if you rebuild with a sorting column set. + // On GTK, wxDVC will crash if we rebuild with a sorting column set. sorting_column->UnsetAsSortKey(); } @@ -457,84 +442,45 @@ void PCB_NET_INSPECTOR_PANEL::buildNetsList( bool rebuildColumns ) buildColumns(); } - m_data_model->deleteAllItems(); - + m_dataModel->deleteAllItems(); m_custom_group_rules.clear(); for( const wxString& rule : cfg->custom_group_rules ) m_custom_group_rules.push_back( std::make_unique( rule, CTX_NET ) ); - m_data_model->addCustomGroups(); + m_dataModel->addCustomGroups(); - std::vector> new_items; + std::vector netCodes; - std::vector prefiltered_cn_items = relevantConnectivityItems(); - - struct NET_INFO + for( NETINFO_ITEM* ni : m_board->GetNetInfo() ) { - int netcode; - NETINFO_ITEM* net; - unsigned int pad_count; - }; - - struct NET_INFO_CMP_LESS - { - bool operator()( const NET_INFO& a, const NET_INFO& b ) const - { - return a.netcode < b.netcode; - } - bool operator()( const NET_INFO& a, int b ) const { return a.netcode < b; } - bool operator()( int a, const NET_INFO& b ) const { return a < b.netcode; } - }; - - std::vector nets; - nets.reserve( m_brd->GetNetInfo().NetsByNetcode().size() ); - - for( const std::pair ni : m_brd->GetNetInfo().NetsByNetcode() ) - { - if( ni.first == 0 ) - m_zero_netitem = ni.second; - - if( netFilterMatches( ni.second, cfg ) ) - nets.emplace_back( NET_INFO{ ni.first, ni.second, 0 } ); + if( netFilterMatches( ni, cfg ) ) + netCodes.emplace_back( ni ); } - // count the pads for each net. since the nets are sorted by netcode - // iterating over the footprints' pads is faster. - for( FOOTPRINT* footprint : m_brd->Footprints() ) - { - for( PAD* pad : footprint->Pads() ) - { - auto i = std::lower_bound( nets.begin(), nets.end(), pad->GetNetCode(), - NET_INFO_CMP_LESS() ); - - if( i != nets.end() && i->netcode == pad->GetNetCode() ) - i->pad_count += 1; - } - } + std::ranges::sort( netCodes, + []( const NETINFO_ITEM* a, const NETINFO_ITEM* b ) + { + return a->GetNetCode() < b->GetNetCode(); + } ); - for( NET_INFO& ni : nets ) - { - if( m_show_zero_pad_nets || ni.pad_count > 0 ) - new_items.emplace_back( buildNewItem( ni.net, ni.pad_count, prefiltered_cn_items ) ); - } + std::vector> lengths = calculateNets( netCodes, m_showZeroPadNets ); - m_data_model->addItems( std::move( new_items ) ); + m_dataModel->addItems( lengths ); - // Re-enable the sorting column + // Try to re-enable the sorting column if( !restoreSortColumn( sorting_column_id, sort_order_asc )) { - // By default sort by Name column + // By default, sort by Name column restoreSortColumn( COLUMN_NAME, true ); } // Try to restore the expanded groups - if( m_board_loaded ) + if( m_boardLoaded ) { - m_row_expanding = true; + m_rowExpanding = true; - std::vector> groupItems = - m_data_model->getGroupDataViewItems(); + std::vector> groupItems = m_dataModel->getGroupDataViewItems(); for( wxString& groupName : cfg->expanded_rows ) { @@ -544,31 +490,25 @@ void PCB_NET_INSPECTOR_PANEL::buildNetsList( bool rebuildColumns ) return groupName == item.first; }; - auto tableItem = std::find_if( groupItems.begin(), groupItems.end(), pred ); + auto tableItem = std::ranges::find_if( groupItems, pred ); if( tableItem != groupItems.end() ) m_netsList->Expand( tableItem->second ); } - m_row_expanding = false; + m_rowExpanding = false; } - // try to restore the selected rows. Set the ones that we can't find any more to -1. + // Try to restore the selected rows sel.Clear(); - for( int& nc : prev_selected_netcodes ) + for( const int& nc : prev_selected_netcodes ) { - std::optional r = m_data_model->findItem( nc ); - - if( r ) + if( std::optional r = m_dataModel->findItem( nc ) ) { const std::unique_ptr& list_item = *r.value(); sel.Add( wxDataViewItem( list_item.get() ) ); } - else - { - nc = -1; - } } if( !sel.IsEmpty() ) @@ -581,9 +521,7 @@ void PCB_NET_INSPECTOR_PANEL::buildNetsList( bool rebuildColumns ) m_netsList->UnselectAll(); } - alg::delete_matching( prev_selected_netcodes, -1 ); - - m_in_build_nets_list = false; + m_inBuildNetsList = false; } @@ -596,14 +534,14 @@ bool PCB_NET_INSPECTOR_PANEL::netFilterMatches( NETINFO_ITEM* aN cfg = &localSettings.m_NetInspectorPanel; } - // Never show the unconnected net + // Never show an unconnected net if( aNet->GetNetCode() <= 0 ) return false; - wxString filterString = UnescapeString( m_searchCtrl->GetValue() ).Upper(); - wxString netName = UnescapeString( aNet->GetNetname() ).Upper(); - NETCLASS* netClass = aNet->GetNetClass(); - wxString netClassName = UnescapeString( netClass->GetName() ).Upper(); + const wxString filterString = UnescapeString( m_searchCtrl->GetValue() ).Upper(); + const wxString netName = UnescapeString( aNet->GetNetname() ).Upper(); + const NETCLASS* netClass = aNet->GetNetClass(); + const wxString netClassName = UnescapeString( netClass->GetName() ).Upper(); bool matched = false; @@ -611,18 +549,18 @@ bool PCB_NET_INSPECTOR_PANEL::netFilterMatches( NETINFO_ITEM* aN if( filterString.Length() == 0 ) matched = true; - // Search on Netclass + // Search on net class if( !matched && cfg->filter_by_netclass && netClassName.Find( filterString ) != wxNOT_FOUND ) matched = true; - // Search on Net name + // Search on net name if( !matched && cfg->filter_by_net_name && netName.Find( filterString ) != wxNOT_FOUND ) matched = true; // Remove unconnected nets if required if( matched ) { - if( !m_show_unconnected_nets ) + if( !m_showUnconnectedNets ) matched = !netName.StartsWith( wxT( "UNCONNECTED-(" ) ); } @@ -640,47 +578,10 @@ struct NETCODE_CMP_LESS }; -std::unique_ptr -PCB_NET_INSPECTOR_PANEL::buildNewItem( NETINFO_ITEM* aNet, unsigned int aPadCount, - const std::vector& aCNItems ) -{ - std::unique_ptr new_item = std::make_unique( aNet ); - - new_item->SetPadCount( aPadCount ); - new_item->SetLayerCount( m_brd->GetCopperLayerCount() ); - - const auto cn_items = std::equal_range( aCNItems.begin(), aCNItems.end(), aNet->GetNetCode(), - NETCODE_CMP_LESS() ); - - for( auto i = cn_items.first; i != cn_items.second; ++i ) - { - BOARD_CONNECTED_ITEM* item = ( *i )->Parent(); - - if( item->Type() == PCB_PAD_T ) - { - new_item->AddPadDieLength( static_cast( item )->GetPadToDieLength() ); - } - else if( PCB_TRACK* track = dynamic_cast( item ) ) - { - new_item->AddLayerWireLength( track->GetLength(), track->GetLayer() ); - - if( item->Type() == PCB_VIA_T ) - { - new_item->AddViaCount( 1 ); - new_item->AddViaLength( calculateViaLength( track ) ); - } - } - } - - return new_item; -} - - std::vector PCB_NET_INSPECTOR_PANEL::relevantConnectivityItems() const { - // pre-filter the connectivity items and sort them by netcode. - // this avoids quadratic runtime when building the whole net list and - // calculating the total length for each net. + // Pre-filter the connectivity items and sort them by netcode. This avoids quadratic runtime when building the whole + // net list. const auto type_bits = std::bitset() .set( PCB_TRACE_T ) .set( PCB_ARC_T ) @@ -690,127 +591,104 @@ std::vector PCB_NET_INSPECTOR_PANEL::relevantConnectivityItems() const std::vector cn_items; cn_items.reserve( 1024 ); - for( CN_ITEM* cn_item : m_brd->GetConnectivity()->GetConnectivityAlgo()->ItemList() ) + for( CN_ITEM* cn_item : m_board->GetConnectivity()->GetConnectivityAlgo()->ItemList() ) { if( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] ) cn_items.push_back( cn_item ); } - std::sort( cn_items.begin(), cn_items.end(), NETCODE_CMP_LESS() ); + std::ranges::sort( cn_items, NETCODE_CMP_LESS() ); return cn_items; } -unsigned int PCB_NET_INSPECTOR_PANEL::calculateViaLength( const PCB_TRACK* aTrack ) const +std::vector> +PCB_NET_INSPECTOR_PANEL::calculateNets( const std::vector& aNetCodes, bool aIncludeZeroPadNets ) const { - const PCB_VIA* via = dynamic_cast( aTrack ); + std::vector> results; - if( !via ) - return 0; + LENGTH_CALCULATION* calc = m_board->GetLengthCalculation(); + const std::vector conItems = relevantConnectivityItems(); - BOARD_DESIGN_SETTINGS& bds = m_brd->GetDesignSettings(); + // First assemble the LENGTH_CALCULATION_ITEMs for board items which match the nets we need to recompute + // Precondition: conItems and aNetCodes are sorted in increasing netcode value + // Functionality: This extracts any items from conItems which have a netcode which is present in aNetCodes + std::unordered_map> netItemsMap; + std::vector foundNets; - // Must be static to keep from raising its ugly head in performance profiles - static std::initializer_list traceAndPadTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T }; + auto itemItr = conItems.begin(); + auto netCodeItr = aNetCodes.begin(); - // calculate the via length individually from the board stackup and via's start and end layer. - if( bds.m_HasStackup ) + while( itemItr != conItems.end() && netCodeItr != aNetCodes.end() ) { - PCB_LAYER_ID top_layer = UNDEFINED_LAYER; - PCB_LAYER_ID bottom_layer = UNDEFINED_LAYER; - LSET layers = bds.GetEnabledLayers(); + const int curNetCode = ( *netCodeItr )->GetNetCode(); + const int curItemNetCode = ( *itemItr )->Net(); - for( auto layer_it = layers.copper_layers_begin(); - layer_it != layers.copper_layers_end(); - ++layer_it ) + if( curItemNetCode == curNetCode ) { - if( m_brd->GetConnectivity()->IsConnectedOnLayer( via, *layer_it, traceAndPadTypes ) ) - { - if( top_layer == UNDEFINED_LAYER ) - top_layer = PCB_LAYER_ID( *layer_it ); - else - bottom_layer = PCB_LAYER_ID( *layer_it ); - } - } + if( foundNets.empty() || foundNets.back() != *netCodeItr ) + foundNets.emplace_back( *netCodeItr ); - if( top_layer == UNDEFINED_LAYER ) - top_layer = via->TopLayer(); - if( bottom_layer == UNDEFINED_LAYER ) - bottom_layer = via->BottomLayer(); - - const BOARD_STACKUP& stackup = bds.GetStackupDescriptor(); - return stackup.GetLayerDistance( top_layer, bottom_layer ); - } - else - { - int dielectricLayers = bds.GetCopperLayerCount() - 1; - // TODO: not all dielectric layers are the same thickness! - int layerThickness = bds.GetBoardThickness() / dielectricLayers; - int effectiveBottomLayer; - - if( via->BottomLayer() == B_Cu ) - effectiveBottomLayer = F_Cu + dielectricLayers; - else - effectiveBottomLayer = via->BottomLayer(); - - int layerCount = effectiveBottomLayer - via->TopLayer(); - - return layerCount * layerThickness; + // Take the item + LENGTH_CALCULATION_ITEM lengthItem = calc->GetLengthCalculationItem( ( *itemItr )->Parent() ); + netItemsMap[curItemNetCode].emplace_back( std::move( lengthItem ) ); + ++itemItr; + } + else if( curItemNetCode < curNetCode ) + { + // Fast-forward through items + while( itemItr != conItems.end() && ( *itemItr )->Net() < curNetCode ) + ++itemItr; + } + else if( curItemNetCode > curNetCode ) + { + // Fast-forward through required net codes + while( netCodeItr != aNetCodes.end() && curItemNetCode > ( *netCodeItr )->GetNetCode() ) + ++netCodeItr; + } } -} + // Now calculate the length statistics for each net. This includes potentially expensive path optimisations, so + // parallelize this work. + std::mutex resultsMutex; + thread_pool& tp = GetKiCadThreadPool(); -void PCB_NET_INSPECTOR_PANEL::updateNet( NETINFO_ITEM* aNet ) -{ - // something for the specified net has changed, update that row. - // ignore nets that are not in our list because the filter doesn't match. - if( !netFilterMatches( aNet ) ) - { - m_data_model->deleteItem( m_data_model->findItem( aNet ) ); - return; - } - - // if the net had no pads before, it might not be in the displayed list yet. - // if it had pads and now doesn't anymore, we might need to remove it from the list. - std::optional cur_net_row = m_data_model->findItem( aNet ); + auto resultsFuture = tp.parallelize_loop( + 0, foundNets.size(), + [&, this, calc]( const int start, const int end ) + { + for( int i = start; i < end; ++i ) + { + int netCode = foundNets[i]->GetNetCode(); - const unsigned int node_count = m_brd->GetNodesCount( aNet->GetNetCode() ); + constexpr PATH_OPTIMISATIONS opts = { .OptimiseViaLayers = true, + .MergeTracks = true, + .OptimiseTracesInPads = true, + .InferViaInPad = false }; + LENGTH_DETAILS lengthDetails = + calc->CalculateLengthDetails( netItemsMap[netCode], opts, nullptr, nullptr, true ); - if( node_count == 0 && !m_show_zero_pad_nets ) - { - m_data_model->deleteItem( cur_net_row ); - return; - } + if( aIncludeZeroPadNets || lengthDetails.NumPads > 0 ) + { + std::unique_ptr new_item = std::make_unique( foundNets[i] ); - std::unique_ptr new_list_item = buildNewItem( aNet, node_count, - relevantConnectivityItems() ); + new_item->SetPadCount( lengthDetails.NumPads ); + new_item->SetLayerCount( m_board->GetCopperLayerCount() ); + new_item->SetPadDieLength( lengthDetails.PadToDieLength ); + new_item->SetViaCount( lengthDetails.NumVias ); + new_item->SetViaLength( lengthDetails.ViaLength ); + new_item->SetLayerWireLengths( *lengthDetails.LayerLengths ); - if( !cur_net_row ) - { - m_data_model->addItem( std::move( new_list_item ) ); - return; - } + std::scoped_lock lock( resultsMutex ); + results.emplace_back( std::move( new_item ) ); + } + } + } ); - const std::unique_ptr& cur_list_item = *cur_net_row.value(); + resultsFuture.get(); - if( cur_list_item->GetNetName() != new_list_item->GetNetName() ) - { - // if the name has changed, it might require re-grouping. - // it's easier to remove and re-insert it - m_data_model->deleteItem( cur_net_row ); - m_data_model->addItem( std::move( new_list_item ) ); - } - else - { - // update fields only - cur_list_item->SetPadCount( new_list_item->GetPadCount() ); - cur_list_item->SetViaCount( new_list_item->GetViaCount() ); - cur_list_item->SetLayerWireLength( new_list_item->GetLayerWireLength() ); - cur_list_item->SetPadDieLength( new_list_item->GetPadDieLength() ); - - updateDisplayedRowValues( cur_net_row ); - } + return results; } @@ -821,33 +699,33 @@ void PCB_NET_INSPECTOR_PANEL::updateNet( NETINFO_ITEM* aNet ) * ***************************************************************************************/ -wxString PCB_NET_INSPECTOR_PANEL::formatNetCode( const NETINFO_ITEM* aNet ) const +wxString PCB_NET_INSPECTOR_PANEL::formatNetCode( const NETINFO_ITEM* aNet ) { return wxString::Format( wxT( "%.3d" ), aNet->GetNetCode() ); } -wxString PCB_NET_INSPECTOR_PANEL::formatNetName( const NETINFO_ITEM* aNet ) const +wxString PCB_NET_INSPECTOR_PANEL::formatNetName( const NETINFO_ITEM* aNet ) { return UnescapeString( aNet->GetNetname() ); } -wxString PCB_NET_INSPECTOR_PANEL::formatCount( unsigned int aValue ) const +wxString PCB_NET_INSPECTOR_PANEL::formatCount( const unsigned int aValue ) { return wxString::Format( wxT( "%u" ), aValue ); } -wxString PCB_NET_INSPECTOR_PANEL::formatLength( int64_t aValue ) const +wxString PCB_NET_INSPECTOR_PANEL::formatLength( const int64_t aValue ) const { - return m_frame->MessageTextFromValue( static_cast( aValue ), + return m_frame->MessageTextFromValue( aValue, // don't include unit label in the string when reporting - !m_in_reporting); + !m_inReporting ); } -void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optional& aRow ) +void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optional& aRow ) const { if( !aRow ) return; @@ -855,7 +733,7 @@ void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optionalGetSelections( sel ); - m_data_model->updateItem( aRow ); + m_dataModel->updateItem( aRow ); if( !sel.IsEmpty() ) { @@ -874,213 +752,163 @@ void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optionalGetBoard(); + m_board = m_frame->GetBoard(); - if( m_brd ) - m_brd->AddListener( this ); + if( m_board ) + m_board->AddListener( this ); - m_board_loaded = true; - m_board_loading = true; + m_boardLoaded = true; + m_boardLoading = true; - PROJECT_LOCAL_SETTINGS& localSettings = Pgm().GetSettingsManager().Prj().GetLocalSettings(); + const PROJECT_LOCAL_SETTINGS& localSettings = Pgm().GetSettingsManager().Prj().GetLocalSettings(); auto& cfg = localSettings.m_NetInspectorPanel; m_searchCtrl->SetValue( cfg.filter_text ); buildNetsList( true ); - m_board_loading = false; + m_boardLoading = false; } + void PCB_NET_INSPECTOR_PANEL::OnBoardItemAdded( BOARD& aBoard, BOARD_ITEM* aBoardItem ) { - if( !IsShownOnScreen() ) - return; + const std::vector item{ aBoardItem }; + updateBoardItems( item ); +} - if( NETINFO_ITEM* net = dynamic_cast( aBoardItem ) ) - { - // a new net has been added to the board. add it to our list if it - // passes the netname filter test. - if( netFilterMatches( net ) ) - { - std::unique_ptr new_item = std::make_unique( net ); +void PCB_NET_INSPECTOR_PANEL::OnBoardItemsAdded( BOARD& aBoard, std::vector& aBoardItems ) +{ + updateBoardItems( aBoardItems ); +} - // the new net could have some pads already assigned, count them. - new_item->SetPadCount( m_brd->GetNodesCount( net->GetNetCode() ) ); - new_item->SetLayerCount( m_brd->GetCopperLayerCount() ); - m_data_model->addItem( std::move( new_item ) ); - } +void PCB_NET_INSPECTOR_PANEL::updateBoardItems( const std::vector& aBoardItems ) +{ + if( !IsShownOnScreen() ) + return; + + // Rebuild full list for large changes + if( aBoardItems.size() + > static_cast( ADVANCED_CFG::GetCfg().m_NetInspectorBulkUpdateOptimisationThreshold ) ) + { + buildNetsList(); } - else if( BOARD_CONNECTED_ITEM* i = dynamic_cast( aBoardItem ) ) + else { - std::optional r = m_data_model->findItem( i->GetNet() ); + std::vector changedNets; - if( r ) + for( BOARD_ITEM* boardItem : aBoardItems ) { - // try to handle frequent operations quickly. - if( PCB_TRACK* track = dynamic_cast( i ) ) + if( NETINFO_ITEM* net = dynamic_cast( boardItem ) ) { - const std::unique_ptr& list_item = *r.value(); - int len = track->GetLength(); - - list_item->AddLayerWireLength( len, track->GetLayer() ); - - if( track->Type() == PCB_VIA_T ) - { - list_item->AddViaCount( 1 ); - list_item->AddViaLength( calculateViaLength( track ) ); - } - - updateDisplayedRowValues( r ); - return; + // A new net has been added to the board. Add it to our list if it passes the netname filter test. + if( netFilterMatches( net ) ) + changedNets.emplace_back( net ); } - } - - // resort to generic slower net update otherwise. - updateNet( i->GetNet() ); - } - else if( FOOTPRINT* footprint = dynamic_cast( aBoardItem ) ) - { - for( const PAD* pad : footprint->Pads() ) - { - std::optional r = m_data_model->findItem( pad->GetNet() ); - - if( !r ) + else if( BOARD_CONNECTED_ITEM* i = dynamic_cast( boardItem ) ) { - // if show-zero-pads is off, we might not have this net - // in our list yet, so add it first. - // notice that at this point we are very certain that this net - // will have at least one pad. - - if( netFilterMatches( pad->GetNet() ) ) - r = m_data_model->addItem( std::make_unique( pad->GetNet() ) ); + changedNets.emplace_back( i->GetNet() ); } - - if( r ) + else if( FOOTPRINT* footprint = dynamic_cast( boardItem ) ) { - const std::unique_ptr& list_item = *r.value(); - int len = pad->GetPadToDieLength(); - - list_item->AddPadCount( 1 ); - list_item->AddPadDieLength( len ); - list_item->SetLayerCount( m_brd->GetCopperLayerCount() ); - - if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets ) - m_data_model->deleteItem( r ); - else - updateDisplayedRowValues( r ); + for( const PAD* pad : footprint->Pads() ) + { + if( netFilterMatches( pad->GetNet() ) ) + changedNets.emplace_back( pad->GetNet() ); + } } } + + std::ranges::sort( changedNets, + []( const NETINFO_ITEM* a, const NETINFO_ITEM* b ) + { + return a->GetNetCode() < b->GetNetCode(); + } ); + + updateNets( changedNets ); } + + m_netsList->Refresh(); } -void PCB_NET_INSPECTOR_PANEL::OnBoardItemsAdded( BOARD& aBoard, - std::vector& aBoardItems ) +void PCB_NET_INSPECTOR_PANEL::updateNets( const std::vector& aNets ) const { - if( !IsShownOnScreen() ) - return; - - const size_t threshold = ADVANCED_CFG::GetCfg().m_NetInspectorBulkUpdateOptimisationThreshold; + std::vector netsToUpdate; + std::unordered_set netsToDelete; - // Rebuild full netlist for large changes - if( aBoardItems.size() > threshold ) + for( NETINFO_ITEM* net : aNets ) { - buildNetsList(); - m_netsList->Refresh(); - } - else - { - for( BOARD_ITEM* item : aBoardItems ) - { - OnBoardItemAdded( aBoard, item ); - } + // Add all nets to the deletion list - we will prune this later to only contain unhandled nets + netsToDelete.insert( net ); + + // Only calculate nets that match the current filter + if( netFilterMatches( net ) ) + netsToUpdate.emplace_back( net ); } -} + m_netsList->Freeze(); -void PCB_NET_INSPECTOR_PANEL::OnBoardItemRemoved( BOARD& aBoard, BOARD_ITEM* aBoardItem ) -{ - if( !IsShownOnScreen() ) - return; + std::vector> newListItems = calculateNets( aNets, true ); - if( NETINFO_ITEM* net = dynamic_cast( aBoardItem ) ) - { - m_data_model->deleteItem( m_data_model->findItem( net ) ); - } - else if( FOOTPRINT* footprint = dynamic_cast( aBoardItem ) ) + for( std::unique_ptr& newListItem : newListItems ) { - for( const PAD* pad : footprint->Pads() ) - { - std::optional r = m_data_model->findItem( pad->GetNet() ); - - if( r ) - { - const std::unique_ptr& list_item = *r.value(); - int len = pad->GetPadToDieLength(); + // Remove the handled net from the deletion list + netsToDelete.erase( newListItem->GetNet() ); - list_item->SubPadCount( 1 ); - list_item->SubPadDieLength( len ); + std::optional curNetRow = m_dataModel->findItem( newListItem->GetNetCode() ); - if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets ) - m_data_model->deleteItem( r ); - else - updateDisplayedRowValues( r ); - } + if( !m_showZeroPadNets && newListItem->GetPadCount() == 0 ) + { + m_dataModel->deleteItem( curNetRow ); + continue; } - } - else if( BOARD_CONNECTED_ITEM* i = dynamic_cast( aBoardItem ) ) - { - std::optional r = m_data_model->findItem( i->GetNet() ); - if( r ) + if( !curNetRow ) { - // try to handle frequent operations quickly. - if( PCB_TRACK* track = dynamic_cast( i ) ) - { - const std::unique_ptr& list_item = *r.value(); - int len = track->GetLength(); + m_dataModel->addItem( std::move( newListItem ) ); + continue; + } - list_item->SubLayerWireLength( len, track->GetLayer() ); + const std::unique_ptr& curListItem = *curNetRow.value(); - if( track->Type() == PCB_VIA_T ) - { - list_item->SubViaCount( 1 ); - list_item->SubViaLength( calculateViaLength( track ) ); - } - - updateDisplayedRowValues( r ); - return; - } + if( curListItem->GetNetName() != newListItem->GetNetName() ) + { + // If the name has changed, it might require re-grouping. It's easier to remove and re-insert it. + m_dataModel->deleteItem( curNetRow ); + m_dataModel->addItem( std::move( newListItem ) ); + } + else + { + curListItem->SetPadCount( newListItem->GetPadCount() ); + curListItem->SetPadDieLength( newListItem->GetPadDieLength() ); + curListItem->SetViaCount( newListItem->GetViaCount() ); + curListItem->SetViaLength( newListItem->GetViaLength() ); + curListItem->SetLayerWireLengths( newListItem->GetLayerWireLengths() ); - // resort to generic slower net update otherwise. - updateNet( i->GetNet() ); + updateDisplayedRowValues( curNetRow ); } } + + // Delete any nets we have not yet handled + for( const NETINFO_ITEM* netToDelete : netsToDelete ) + m_dataModel->deleteItem( m_dataModel->findItem( netToDelete->GetNetCode() ) ); + + m_netsList->Thaw(); } -void PCB_NET_INSPECTOR_PANEL::OnBoardItemsRemoved( BOARD& aBoard, - std::vector& aBoardItems ) +void PCB_NET_INSPECTOR_PANEL::OnBoardItemRemoved( BOARD& aBoard, BOARD_ITEM* aBoardItem ) { - if( !IsShownOnScreen() ) - return; + const std::vector item{ aBoardItem }; + updateBoardItems( item ); +} - const size_t threshold = ADVANCED_CFG::GetCfg().m_NetInspectorBulkUpdateOptimisationThreshold; - if( aBoardItems.size() > threshold ) - { - buildNetsList(); - m_netsList->Refresh(); - } - else - { - for( BOARD_ITEM* item : aBoardItems ) - { - OnBoardItemRemoved( aBoard, item ); - } - } +void PCB_NET_INSPECTOR_PANEL::OnBoardItemsRemoved( BOARD& aBoard, std::vector& aBoardItems ) +{ + updateBoardItems( aBoardItems ); } @@ -1090,32 +918,20 @@ void PCB_NET_INSPECTOR_PANEL::OnBoardNetSettingsChanged( BOARD& aBoard ) return; buildNetsList(); - m_netsList->Refresh(); } void PCB_NET_INSPECTOR_PANEL::OnBoardItemChanged( BOARD& aBoard, BOARD_ITEM* aBoardItem ) { - if( !IsShownOnScreen() ) - return; - - if( dynamic_cast( aBoardItem ) != nullptr - || dynamic_cast( aBoardItem ) != nullptr ) - { - buildNetsList(); - m_netsList->Refresh(); - } + const std::vector item{ aBoardItem }; + updateBoardItems( item ); } void PCB_NET_INSPECTOR_PANEL::OnBoardItemsChanged( BOARD& aBoard, std::vector& aBoardItems ) { - if( !IsShownOnScreen() ) - return; - - buildNetsList(); - m_netsList->Refresh(); + updateBoardItems( aBoardItems ); } @@ -1127,45 +943,32 @@ void PCB_NET_INSPECTOR_PANEL::OnBoardCompositeUpdate( BOARD& if( !IsShownOnScreen() ) return; - const size_t threshold = ADVANCED_CFG::GetCfg().m_NetInspectorBulkUpdateOptimisationThreshold; - - // Rebuild the full list if the number of items affected is > the optimisation threshold - // Note: Always rebuild for any changed items as there is no way to determine what property - // of the item has changed in the net inspector data model - if( aChangedItems.size() > 0 || aAddedItems.size() > threshold - || aRemovedItems.size() > threshold ) - { - buildNetsList(); - } - else - { - OnBoardItemsAdded( aBoard, aAddedItems ); - OnBoardItemsRemoved( aBoard, aRemovedItems ); - } - - m_netsList->Refresh(); + std::vector allItems{ aAddedItems.begin(), aAddedItems.end() }; + allItems.insert( allItems.end(), aRemovedItems.begin(), aRemovedItems.end() ); + allItems.insert( allItems.end(), aChangedItems.begin(), aChangedItems.end() ); + updateBoardItems( allItems ); } void PCB_NET_INSPECTOR_PANEL::OnBoardHighlightNetChanged( BOARD& aBoard ) { - if( m_highlighting_nets || !IsShownOnScreen() ) + if( m_highlightingNets || !IsShownOnScreen() ) return; - if( !m_brd->IsHighLightNetON() ) + if( !m_board->IsHighLightNetON() ) { m_netsList->UnselectAll(); } else { - const std::set& selected_codes = m_brd->GetHighLightNetCodes(); + const std::set& selected_codes = m_board->GetHighLightNetCodes(); wxDataViewItemArray new_selection; new_selection.Alloc( selected_codes.size() ); - for( int code : selected_codes ) + for( const int code : selected_codes ) { - if( std::optional r = m_data_model->findItem( code ) ) + if( std::optional r = m_dataModel->findItem( code ) ) new_selection.Add( wxDataViewItem( &***r ) ); } @@ -1186,7 +989,7 @@ void PCB_NET_INSPECTOR_PANEL::OnBoardHighlightNetChanged( BOARD& aBoard ) void PCB_NET_INSPECTOR_PANEL::OnShowPanel() { buildNetsList(); - OnBoardHighlightNetChanged( *m_brd ); + OnBoardHighlightNetChanged( *m_board ); } @@ -1266,7 +1069,7 @@ void PCB_NET_INSPECTOR_PANEL::OnNetsListContextMenu( wxDataViewEvent& event ) if( !selItem || !selItem->GetIsGroup() ) removeSelectedGroup->Enable( false ); - menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this ); + menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this ); PopupMenu( &menu ); } @@ -1300,11 +1103,11 @@ void PCB_NET_INSPECTOR_PANEL::onAddGroup() if( newGroupName == "" ) return; - if( std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(), - [&]( std::unique_ptr& rule ) - { - return rule->GetPattern() == newGroupName; - } ) + if( std::ranges::find_if( m_custom_group_rules, + [&]( std::unique_ptr& rule ) + { + return rule->GetPattern() == newGroupName; + } ) == m_custom_group_rules.end() ) { m_custom_group_rules.push_back( std::make_unique( newGroupName, @@ -1318,19 +1121,19 @@ void PCB_NET_INSPECTOR_PANEL::onAddGroup() void PCB_NET_INSPECTOR_PANEL::onClearHighlighting() { - m_highlighting_nets = true; + m_highlightingNets = true; m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings()->SetHighlight( false ); m_frame->GetCanvas()->GetView()->UpdateAllLayersColor(); m_frame->GetCanvas()->Refresh(); - m_highlighting_nets = false; + m_highlightingNets = false; } void PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow( wxCommandEvent& event ) { - if( !m_row_expanding ) + if( !m_rowExpanding ) SaveSettings(); } @@ -1339,7 +1142,7 @@ void PCB_NET_INSPECTOR_PANEL::OnHeaderContextMenu( wxCommandEvent& event ) { wxMenu menu; generateShowHideColumnMenu( &menu ); - menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this ); + menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this ); PopupMenu( &menu ); } @@ -1384,7 +1187,7 @@ void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event ) _( "Group by Netclass" ), wxEmptyString, wxITEM_CHECK ); menu.Append( groupNetclass ); - groupNetclass->Check( m_group_by_netclass ); + groupNetclass->Check( m_groupByNetclass ); menu.AppendSeparator(); @@ -1412,13 +1215,13 @@ void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event ) _( "Show Zero Pad Nets" ), wxEmptyString, wxITEM_CHECK ); menu.Append( showZeroNetPads ); - showZeroNetPads->Check( m_show_zero_pad_nets ); + showZeroNetPads->Check( m_showZeroPadNets ); wxMenuItem* showUnconnectedNets = new wxMenuItem( &menu, ID_SHOW_UNCONNECTED_NETS, _( "Show Unconnected Nets" ), wxEmptyString, wxITEM_CHECK ); menu.Append( showUnconnectedNets ); - showUnconnectedNets->Check( m_show_unconnected_nets ); + showUnconnectedNets->Check( m_showUnconnectedNets ); menu.AppendSeparator(); @@ -1435,7 +1238,7 @@ void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event ) generateShowHideColumnMenu( colsMenu ); menu.AppendSubMenu( colsMenu, _( "Show / Hide Columns" ) ); - menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this ); + menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this ); PopupMenu( &menu ); } @@ -1465,7 +1268,7 @@ void PCB_NET_INSPECTOR_PANEL::generateShowHideColumnMenu( wxMenu* target ) } -void PCB_NET_INSPECTOR_PANEL::onSettingsMenu( wxCommandEvent& event ) +void PCB_NET_INSPECTOR_PANEL::onContextMenuSelection( wxCommandEvent& event ) { bool saveAndRebuild = true; @@ -1487,21 +1290,13 @@ void PCB_NET_INSPECTOR_PANEL::onSettingsMenu( wxCommandEvent& event ) onAddGroup(); break; - case ID_GROUP_BY_CONSTRAINT: - m_group_by_constraint = !m_group_by_constraint; - break; + case ID_GROUP_BY_CONSTRAINT: m_groupByConstraint = !m_groupByConstraint; break; - case ID_GROUP_BY_NETCLASS: - m_group_by_netclass = !m_group_by_netclass; - break; + case ID_GROUP_BY_NETCLASS: m_groupByNetclass = !m_groupByNetclass; break; - case ID_FILTER_BY_NET_NAME: - m_filter_by_net_name = !m_filter_by_net_name; - break; + case ID_FILTER_BY_NET_NAME: m_filterByNetName = !m_filterByNetName; break; - case ID_FILTER_BY_NETCLASS: - m_filter_by_netclass = !m_filter_by_netclass; - break; + case ID_FILTER_BY_NETCLASS: m_filterByNetclass = !m_filterByNetclass; break; case ID_REMOVE_SELECTED_GROUP: onRemoveSelectedGroup(); @@ -1511,13 +1306,9 @@ void PCB_NET_INSPECTOR_PANEL::onSettingsMenu( wxCommandEvent& event ) m_custom_group_rules.clear(); break; - case ID_SHOW_ZERO_NET_PADS: - m_show_zero_pad_nets = !m_show_zero_pad_nets; - break; + case ID_SHOW_ZERO_NET_PADS: m_showZeroPadNets = !m_showZeroPadNets; break; - case ID_SHOW_UNCONNECTED_NETS: - m_show_unconnected_nets = !m_show_unconnected_nets; - break; + case ID_SHOW_UNCONNECTED_NETS: m_showUnconnectedNets = !m_showUnconnectedNets; break; case ID_GENERATE_REPORT: generateReport(); @@ -1562,12 +1353,12 @@ void PCB_NET_INSPECTOR_PANEL::onRemoveSelectedGroup() if( selItem->GetIsGroup() ) { - wxString groupName = selItem->GetGroupName(); - auto groupIter = std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(), - [&]( std::unique_ptr& rule ) - { - return rule->GetPattern() == groupName; - } ); + const wxString groupName = selItem->GetGroupName(); + const auto groupIter = std::ranges::find_if( m_custom_group_rules, + [&]( std::unique_ptr& rule ) + { + return rule->GetPattern() == groupName; + } ); if( groupIter != m_custom_group_rules.end() ) { @@ -1595,7 +1386,7 @@ void PCB_NET_INSPECTOR_PANEL::generateReport() wxString txt; - m_in_reporting = true; + m_inReporting = true; // Print Header: for( auto&& col : m_columns ) @@ -1619,11 +1410,11 @@ void PCB_NET_INSPECTOR_PANEL::generateReport() f.AddLine( txt ); // Print list of nets: - const unsigned int num_rows = m_data_model->itemCount(); + const unsigned int num_rows = m_dataModel->itemCount(); for( unsigned int row = 0; row < num_rows; row++ ) { - auto& i = m_data_model->itemAt( row ); + auto& i = m_dataModel->itemAt( row ); if( i.GetIsGroup() || i.GetNetCode() == 0 ) continue; @@ -1633,15 +1424,15 @@ void PCB_NET_INSPECTOR_PANEL::generateReport() for( auto&& col : m_columns ) { if( static_cast( col.csv_flags ) & static_cast( CSV_COLUMN_DESC::CSV_QUOTE ) ) - txt += '"' + m_data_model->valueAt( col.num, row ).GetString() + wxT( "\";" ); + txt += '"' + m_dataModel->valueAt( col.num, row ).GetString() + wxT( "\";" ); else - txt += m_data_model->valueAt( col.num, row ).GetString() + ';'; + txt += m_dataModel->valueAt( col.num, row ).GetString() + ';'; } f.AddLine( txt ); } - m_in_reporting = false; + m_inReporting = false; f.Write(); f.Close(); @@ -1657,10 +1448,10 @@ void PCB_NET_INSPECTOR_PANEL::OnNetsListItemActivated( wxDataViewEvent& event ) void PCB_NET_INSPECTOR_PANEL::highlightSelectedNets() { // ignore selection changes while the whole list is being rebuilt. - if( m_in_build_nets_list ) + if( m_inBuildNetsList ) return; - m_highlighting_nets = true; + m_highlightingNets = true; RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings(); @@ -1694,22 +1485,21 @@ void PCB_NET_INSPECTOR_PANEL::highlightSelectedNets() m_frame->GetCanvas()->GetView()->UpdateAllLayersColor(); m_frame->GetCanvas()->Refresh(); - m_highlighting_nets = false; + m_highlightingNets = false; } void PCB_NET_INSPECTOR_PANEL::OnColumnSorted( wxDataViewEvent& event ) { - if( !m_in_build_nets_list ) + if( !m_inBuildNetsList ) SaveSettings(); } void PCB_NET_INSPECTOR_PANEL::OnParentSetupChanged() { - // Rebuilt the nets list, and force rebuild of columns in case the stackup has chanaged + // Rebuilt the nets list, and force rebuild of columns in case the stackup has changed buildNetsList( true ); - m_netsList->Refresh(); } @@ -1728,7 +1518,7 @@ void PCB_NET_INSPECTOR_PANEL::onAddNet() newNetName = dlg.GetValue(); - if( m_brd->FindNet( newNetName ) ) + if( m_board->FindNet( newNetName ) ) { DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ), newNetName ) ); @@ -1740,9 +1530,9 @@ void PCB_NET_INSPECTOR_PANEL::onAddNet() } } - NETINFO_ITEM* newnet = new NETINFO_ITEM( m_brd, dlg.GetValue(), 0 ); + NETINFO_ITEM* newnet = new NETINFO_ITEM( m_board, dlg.GetValue(), 0 ); - m_brd->Add( newnet ); + m_board->Add( newnet ); // We'll get an OnBoardItemAdded callback from this to update our listbox m_frame->OnModify(); @@ -1796,7 +1586,7 @@ void PCB_NET_INSPECTOR_PANEL::onRenameSelectedNet() shortNetName = EscapeString( unescapedShortName, CTX_NETNAME ); fullNetName = netPath + shortNetName; - if( m_brd->FindNet( shortNetName ) || m_brd->FindNet( fullNetName ) ) + if( m_board->FindNet( shortNetName ) || m_board->FindNet( fullNetName ) ) { DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ), unescapedShortName ) ); @@ -1817,11 +1607,11 @@ void PCB_NET_INSPECTOR_PANEL::onRenameSelectedNet() } // the changed name might require re-grouping. remove/re-insert is easier. - auto removed_item = m_data_model->deleteItem( m_data_model->findItem( net ) ); + auto removed_item = m_dataModel->deleteItem( m_dataModel->findItem( net ) ); - m_brd->Remove( net ); + m_board->Remove( net ); net->SetNetname( fullNetName ); - m_brd->Add( net ); + m_board->Add( net ); for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() ) { @@ -1831,7 +1621,7 @@ void PCB_NET_INSPECTOR_PANEL::onRenameSelectedNet() buildNetsList(); - if( std::optional r = m_data_model->findItem( net ) ) + if( std::optional r = m_dataModel->findItem( net ) ) m_netsList->Select( wxDataViewItem( r.value()->get() ) ); m_frame->OnModify(); @@ -1883,7 +1673,7 @@ void PCB_NET_INSPECTOR_PANEL::onDeleteSelectedNet() return 0; } ); - m_brd->Remove( i->GetNet() ); + m_board->Remove( i->GetNet() ); m_frame->OnModify(); // We'll get an OnBoardItemRemoved callback from this to update our listbox @@ -1928,13 +1718,13 @@ void PCB_NET_INSPECTOR_PANEL::OnLanguageChangedImpl() { SaveSettings(); buildNetsList( true ); - m_data_model->updateAllItems(); + m_dataModel->updateAllItems(); } void PCB_NET_INSPECTOR_PANEL::onUnitsChanged( wxCommandEvent& event ) { - m_data_model->updateAllItems(); + m_dataModel->updateAllItems(); event.Skip(); } @@ -1952,13 +1742,13 @@ void PCB_NET_INSPECTOR_PANEL::SaveSettings() // Events fire while we set up the panel which overwrite the settings we haven't yet loaded. bool displayed = false; - for( unsigned int ii = 0; ii < m_data_model->columnCount() && !displayed; ++ii ) + for( unsigned int ii = 0; ii < m_dataModel->columnCount() && !displayed; ++ii ) { if( m_netsList->GetColumn( ii )->GetWidth() > 0 ) displayed = true; } - if( !displayed || !m_board_loaded || m_board_loading ) + if( !displayed || !m_boardLoaded || m_boardLoading ) return; PROJECT_LOCAL_SETTINGS& localSettings = Pgm().GetSettingsManager().Prj().GetLocalSettings(); @@ -1966,12 +1756,12 @@ void PCB_NET_INSPECTOR_PANEL::SaveSettings() // User-defined filters / grouping cfg.filter_text = m_searchCtrl->GetValue(); - cfg.filter_by_net_name = m_filter_by_net_name; - cfg.filter_by_netclass = m_filter_by_netclass; - cfg.group_by_netclass = m_group_by_netclass; - cfg.group_by_constraint = m_group_by_constraint; - cfg.show_zero_pad_nets = m_show_zero_pad_nets; - cfg.show_unconnected_nets = m_show_unconnected_nets; + cfg.filter_by_net_name = m_filterByNetName; + cfg.filter_by_netclass = m_filterByNetclass; + cfg.group_by_netclass = m_groupByNetclass; + cfg.group_by_constraint = m_groupByConstraint; + cfg.show_zero_pad_nets = m_showZeroPadNets; + cfg.show_unconnected_nets = m_showUnconnectedNets; // Grid sorting wxDataViewColumn* sortingCol = m_netsList->GetSortingColumn(); @@ -1979,11 +1769,11 @@ void PCB_NET_INSPECTOR_PANEL::SaveSettings() cfg.sort_order_asc = sortingCol ? sortingCol->IsSortOrderAscending() : true; // Column arrangement / sizes - cfg.col_order.resize( m_data_model->columnCount() ); - cfg.col_widths.resize( m_data_model->columnCount() ); - cfg.col_hidden.resize( m_data_model->columnCount() ); + cfg.col_order.resize( m_dataModel->columnCount() ); + cfg.col_widths.resize( m_dataModel->columnCount() ); + cfg.col_hidden.resize( m_dataModel->columnCount() ); - for( unsigned int ii = 0; ii < m_data_model->columnCount(); ++ii ) + for( unsigned int ii = 0; ii < m_dataModel->columnCount(); ++ii ) { cfg.col_order[ii] = (int) m_netsList->GetColumn( ii )->GetModelColumn(); cfg.col_widths[ii] = m_netsList->GetColumn( ii )->GetWidth(); @@ -1992,8 +1782,7 @@ void PCB_NET_INSPECTOR_PANEL::SaveSettings() // Expanded rows cfg.expanded_rows.clear(); - std::vector> groupItems = - m_data_model->getGroupDataViewItems(); + std::vector> groupItems = m_dataModel->getGroupDataViewItems(); for( std::pair& item : groupItems ) { diff --git a/pcbnew/widgets/pcb_net_inspector_panel.h b/pcbnew/widgets/pcb_net_inspector_panel.h index a6d2b2dd36..3fcb87100a 100644 --- a/pcbnew/widgets/pcb_net_inspector_panel.h +++ b/pcbnew/widgets/pcb_net_inspector_panel.h @@ -37,25 +37,10 @@ class PCB_TRACK; class EDA_COMBINED_MATCHER; /** - * Net inspection panel for pcbnew + * PCB net inspection panel * - * Provides a read-only view of net information, such as routed lengths. Data is updated after - * every change of board items. Note that there is not always a 1:1 relationship between Nets and - * displayed items in the inspector.. This can be the case where there is a constraint which - * selects sub-sections of nets, for example consider a netclass used for a fly-by-routing - * adddress bus. There could be two constraints, e.g.: - *

- * FROM/TO=IC1-IC2, Netclass=DDR_ADDR, Net=ADDR_0 - * FROM/TO=IC2-IC3, Netclass=DDR_ADDR, Net=ADDR_0 - *

- * In this instance, a single address net within the DDR_ADDR netclass could have three entries in - * the inspector, each tracking a different set of net statistics: - *

- * 1. The whole net - * 2. IC1-IC2 - * 3. IC2-IC3 - *

- * In this instance, all sub-nets as a result of a constraint will be grouped by the constraint. + * Provides a read-only view of net information, such as routed lengths. Data is updated after every change of board + * items. */ class PCB_NET_INSPECTOR_PANEL : public NET_INSPECTOR_PANEL, public BOARD_LISTENER { @@ -68,50 +53,41 @@ public: * * Called by PCB_EDIT_FRAME after displaying the Board Setup dialog */ - virtual void OnParentSetupChanged() override; + void OnParentSetupChanged() override; /* * BOARD_LISTENER implementation */ - virtual void OnBoardItemAdded( BOARD& aBoard, BOARD_ITEM* aBoardItem ) override; - virtual void OnBoardItemsAdded( BOARD& aBoard, std::vector& aBoardItems ) override; - virtual void OnBoardItemRemoved( BOARD& aBoard, BOARD_ITEM* aBoardItem ) override; - virtual void OnBoardItemsRemoved( BOARD& aBoard, - std::vector& aBoardItems ) override; - virtual void OnBoardNetSettingsChanged( BOARD& aBoard ) override; - virtual void OnBoardItemChanged( BOARD& aBoard, BOARD_ITEM* aBoardItem ) override; - virtual void OnBoardItemsChanged( BOARD& aBoard, - std::vector& aBoardItems ) override; - virtual void OnBoardHighlightNetChanged( BOARD& aBoard ) override; - virtual void OnBoardCompositeUpdate( BOARD& aBoard, std::vector& aAddedItems, - std::vector& aRemovedItems, - std::vector& aChangedItems ) override; - /** - * Update panel when board is changed - */ - virtual void OnBoardChanged() override; - - /** - * Prepare the panel when shown in the editor - */ - virtual void OnShowPanel() override; - - /** - * Persist the net inspector configuration to project / global settings - */ - virtual void SaveSettings() override; + void OnBoardItemAdded( BOARD& aBoard, BOARD_ITEM* aBoardItem ) override; + void OnBoardItemsAdded( BOARD& aBoard, std::vector& aBoardItems ) override; + void OnBoardItemRemoved( BOARD& aBoard, BOARD_ITEM* aBoardItem ) override; + void OnBoardItemsRemoved( BOARD& aBoard, std::vector& aBoardItems ) override; + void OnBoardNetSettingsChanged( BOARD& aBoard ) override; + void OnBoardItemChanged( BOARD& aBoard, BOARD_ITEM* aBoardItem ) override; + void OnBoardItemsChanged( BOARD& aBoard, std::vector& aBoardItems ) override; + void OnBoardHighlightNetChanged( BOARD& aBoard ) override; + void OnBoardCompositeUpdate( BOARD& aBoard, std::vector& aAddedItems, + std::vector& aRemovedItems, + std::vector& aChangedItems ) override; + + /// Update panel when board is changed + void OnBoardChanged() override; + + /// Prepare the panel when shown in the editor + void OnShowPanel() override; + + /// Persist the net inspector configuration to project / global settings + void SaveSettings() override; protected: - /** - * Reloads strings on an application language change - */ - virtual void OnLanguageChangedImpl() override; + /// Reloads strings on an application language change + void OnLanguageChangedImpl() override; /* * UI events */ - virtual void OnSearchTextChanged( wxCommandEvent& event ) override; - virtual void OnConfigButton( wxCommandEvent& event ) override; + void OnSearchTextChanged( wxCommandEvent& event ) override; + void OnConfigButton( wxCommandEvent& event ) override; void OnExpandCollapseRow( wxCommandEvent& event ); void OnHeaderContextMenu( wxCommandEvent& event ); void OnNetsListContextMenu( wxDataViewEvent& event ); @@ -119,42 +95,36 @@ protected: void OnColumnSorted( wxDataViewEvent& event ); private: + /// Updates displayed statistics for the given nets + void updateNets( const std::vector& aNets ) const; + + /// Unified handling of added / deleted / modified board items + void updateBoardItems( const std::vector& aBoardItems ); + /* - * Helper methods for returning fornatted data + * Helper methods for returning formatted data */ - wxString formatNetCode( const NETINFO_ITEM* aNet ) const; - wxString formatNetName( const NETINFO_ITEM* aNet ) const; - wxString formatCount( unsigned int aValue ) const; + static wxString formatNetCode( const NETINFO_ITEM* aNet ); + static wxString formatNetName( const NETINFO_ITEM* aNet ); + static wxString formatCount( unsigned int aValue ); wxString formatLength( int64_t aValue ) const; - /** - * Generates a sub-menu for the show / hide columns submenu - */ + /// Generates a sub-menu for the show / hide columns submenu void generateShowHideColumnMenu( wxMenu* target ); - /** - * Filters connectivity items from a board update to remove those not related to - * net / track metrics - */ + /// Fetches an ordered (by NetCode) list of all board connectivity items std::vector relevantConnectivityItems() const; - /** - * Filter to determine whether a board net should be included in the net inspector - */ + /// Filter to determine whether a board net should be included in the net inspector bool netFilterMatches( NETINFO_ITEM* aNet, PANEL_NET_INSPECTOR_SETTINGS* cfg = nullptr ) const; - /** - * Updates the stored LIST_ITEMs for a given updated board net item - */ - void updateNet( NETINFO_ITEM* aNet ); - - /** - * Calculates the length of a via from the board stackup - */ - unsigned int calculateViaLength( const PCB_TRACK* ) const; - + /// Rebuilds the net inspector list, removing all previous entries void buildNetsList( bool rebuildColumns = false ); + + /// Build the required columns in the net inspector grid void buildColumns(); + + /// Set sensible default column widths void setColumnWidths(); /** @@ -162,7 +132,7 @@ private: * * @param cfg the PANEL_NET_INSPECTOR_SETTINGS from which to read column widths */ - void adjustListColumnSizes( PANEL_NET_INSPECTOR_SETTINGS* cfg ); + void adjustListColumnSizes( PANEL_NET_INSPECTOR_SETTINGS* cfg ) const; /** * Sets the sort column in the grid to that showing the given model ID column @@ -171,7 +141,7 @@ private: * @param sortOrderAsc True for ascending sort, False for descending sort * @returns true if the column was found */ - bool restoreSortColumn( int sortingColumnId, bool sortOrderAsc ); + bool restoreSortColumn( int sortingColumnId, bool sortOrderAsc ) const; /** * Fetches the displayed grid view column for the given model column ID @@ -179,81 +149,84 @@ private: * @param columnId The ID (from column static IDs enum) to find * @returns Pointer to the wxDataViewColumn, or nullptr if not found */ - wxDataViewColumn* getDisplayedColumnForModelField( int columnId ); + wxDataViewColumn* getDisplayedColumnForModelField( int columnId ) const; - /** - * Generates a CSV report from currently disaplyed data - */ + /// Generates a CSV report from currently disaplyed data void generateReport(); - /** - * Highlight the currently selected net - */ + /// Highlight the currently selected net void highlightSelectedNets(); + /// Handle an application-level change of units void onUnitsChanged( wxCommandEvent& event ); - void onSettingsMenu( wxCommandEvent& event ); + + /// Handle a net row(s) context menu selection + void onContextMenuSelection( wxCommandEvent& event ); + + /// Display a new row(s) context menu void onItemContextMenu( wxCommandEvent& event ); + + /// Adds a new user-specified net to the board void onAddNet(); + + /// Renames a selected net void onRenameSelectedNet(); + + /// Deletes a selected net void onDeleteSelectedNet(); - void onRemoveSelectedGroup(); + + /// Adds a custom display grouping of nets void onAddGroup(); + + /// Removes a custom display grouping + void onRemoveSelectedGroup(); + + /// Clears highlighting from nets void onClearHighlighting(); - /** - * Container class for a set of net data - */ + /// Forward declaration: container class for a set of net data class LIST_ITEM; /** - * Ordered comparison of LIST_ITEMs by net code - */ + * Calculates the length statistics for each given netcode + * + * @param aNetCodes is the list of netcodes to calculate statistics for. This must be sorted in ascending netcode order + * @param aIncludeZeroPadNets determines whether the results should include nets with no pads + * @returns a map of net code to net length detail objects +*/ + std::vector> calculateNets( const std::vector& aNetCodes, + bool aIncludeZeroPadNets ) const; + + /// Ordered comparison of LIST_ITEMs by net code struct LIST_ITEM_NETCODE_CMP_LESS; - /** - * Ordered comparison of LIST_ITEMs by group number - */ + /// Ordered comparison of LIST_ITEMs by group number struct LIST_ITEM_GROUP_NUMBER_CMP_LESS; using LIST_ITEM_ITER = std::vector>::iterator; using LIST_ITEM_CONST_ITER = std::vector>::const_iterator; - /** - * Constructs a LIST_ITEM for storage in the data model from a board net item - */ - std::unique_ptr buildNewItem( NETINFO_ITEM* aNet, unsigned int aPadCount, - const std::vector& aCNItems ); - - void updateDisplayedRowValues( const std::optional& aRow ); + /// Refreshes displayed data for the given rows + void updateDisplayedRowValues( const std::optional& aRow ) const; - // special zero-netcode item. Unconnected pads etc might use different - // (dummy) NETINFO_ITEM. Redirect all of them to this item, which we get - // from the board object in buildNetsList. - NETINFO_ITEM* m_zero_netitem; + /// Parent BOARD + BOARD* m_board = nullptr; - /* - * Current board and parent edit frame - */ - BOARD* m_brd = nullptr; + /// Owning edit frame PCB_EDIT_FRAME* m_frame = nullptr; - /** - * Data model which holds LIST_ITEMs - */ + /// Data model which holds LIST_ITEMs class DATA_MODEL; - /* - * The bound data model to display - */ - wxObjectDataPtr m_data_model; + /// The bound data model to display + wxObjectDataPtr m_dataModel; friend DATA_MODEL; /* * Status flags set during reporting and net rebuild operations */ - bool m_in_reporting = false; - bool m_in_build_nets_list = false; + bool m_inReporting = false; + bool m_inBuildNetsList = false; /* * Status flags to indicate whether a board has been loaded in this control's @@ -264,41 +237,36 @@ private: * settings calculated from an empty board. We do not save settings until the first * board load operation has occured. */ - bool m_board_loaded = false; - bool m_board_loading = false; + bool m_boardLoaded = false; + bool m_boardLoading = false; /* * Flags to indicate whether certain events should be disabled during programmatic updates */ - bool m_row_expanding = false; - bool m_highlighting_nets = false; + bool m_rowExpanding = false; + bool m_highlightingNets = false; /* * Configuration flags - these are all persisted to the project storage */ - bool m_filter_by_net_name = true; - bool m_filter_by_netclass = true; - bool m_show_zero_pad_nets = false; - bool m_show_unconnected_nets = false; - bool m_group_by_netclass = false; - bool m_group_by_constraint = false; - - int m_num_copper_layers = 0; - + bool m_filterByNetName = true; + bool m_filterByNetclass = true; + bool m_showZeroPadNets = false; + bool m_showUnconnectedNets = false; + bool m_groupByNetclass = false; + bool m_groupByConstraint = false; + + /// Custom net grouping rules std::vector> m_custom_group_rules; - /** - * CSV output control - */ + /// CSV output control enum class CSV_COLUMN_DESC : int { CSV_NONE = 0, CSV_QUOTE = 1 << 0 }; - /** - * Column metadata - */ + /// Column metadata struct COLUMN_DESC { COLUMN_DESC( unsigned aNum, PCB_LAYER_ID aLayer, const wxString& aDisp, @@ -324,9 +292,7 @@ private: */ std::vector m_columns; - /* - * Column static IDs. Used to refer to columns as use re-ordering can occur. - */ + /// Column static IDs. Used to refer to columns as user re-ordering can occur enum { COLUMN_NAME = 0, @@ -340,9 +306,7 @@ private: COLUMN_LAST_STATIC_COL = COLUMN_PAD_COUNT }; - /* - * Popup menu item IDs - */ + /// Popup menu item IDs enum POPUP_MENU_OPTIONS { ID_ADD_NET = ID_POPUP_MENU_START, diff --git a/pcbnew/widgets/pcb_net_inspector_panel_data_model.h b/pcbnew/widgets/pcb_net_inspector_panel_data_model.h index 7f79c76b0f..6949a38a41 100644 --- a/pcbnew/widgets/pcb_net_inspector_panel_data_model.h +++ b/pcbnew/widgets/pcb_net_inspector_panel_data_model.h @@ -152,7 +152,7 @@ public: m_via_count -= aValue; } - uint64_t GetViaLength() const { return m_via_length; } + int64_t GetViaLength() const { return m_via_length; } bool ViaLengthChanged() const { return m_column_changed[COLUMN_VIA_LENGTH]; } @@ -174,7 +174,7 @@ public: m_via_length += aValue; } - void SubViaLength( uint64_t aValue ) + void SubViaLength( int64_t aValue ) { if( m_parent ) m_parent->SubViaLength( aValue ); @@ -183,9 +183,9 @@ public: m_via_length -= aValue; } - uint64_t GetBoardWireLength() const + int64_t GetBoardWireLength() const { - uint64_t retval = 0; + int64_t retval = 0; for( auto& [layer, length] : m_layer_wire_length ) retval += length; @@ -193,7 +193,7 @@ public: return retval; } - uint64_t GetLayerWireLength( PCB_LAYER_ID aLayer ) const + int64_t GetLayerWireLength( PCB_LAYER_ID aLayer ) const { auto it = m_layer_wire_length.find( aLayer ); return it != m_layer_wire_length.end() ? it->second : 0; @@ -201,7 +201,7 @@ public: bool BoardWireLengthChanged() const { return m_column_changed[COLUMN_BOARD_LENGTH]; } - void SetLayerWireLength( const uint64_t aValue, PCB_LAYER_ID aLayer ) + void SetLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer ) { auto it = m_layer_wire_length.find( aLayer ); @@ -219,14 +219,23 @@ public: length = aValue; } - std::map GetLayerWireLength() const { return m_layer_wire_length; } + std::map GetLayerWireLengths() const { return m_layer_wire_length; } - void SetLayerWireLength( const std::map& aValue ) + void SetLayerWireLengths( const std::map& aValue ) { + if( m_parent ) + { + for( auto& [oldLayer, oldLength] : m_layer_wire_length ) + m_parent->SubLayerWireLength( oldLength, oldLayer ); + + for( auto& [newLayer, newLength] : aValue ) + m_parent->AddLayerWireLength( newLength, newLayer ); + } + m_layer_wire_length = aValue; } - void AddLayerWireLength( const uint64_t aValue, PCB_LAYER_ID aLayer ) + void AddLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer ) { if( m_parent ) m_parent->AddLayerWireLength( aValue, aLayer ); @@ -235,7 +244,7 @@ public: m_layer_wire_length[aLayer] += aValue; } - void SubLayerWireLength( const uint64_t aValue, PCB_LAYER_ID aLayer ) + void SubLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer ) { if( m_parent ) m_parent->SubLayerWireLength( aValue, aLayer ); @@ -244,11 +253,11 @@ public: m_layer_wire_length[aLayer] -= aValue; } - uint64_t GetPadDieLength() const { return m_pad_die_length; } + int64_t GetPadDieLength() const { return m_pad_die_length; } bool PadDieLengthChanged() const { return m_column_changed[COLUMN_PAD_DIE_LENGTH]; } - void SetPadDieLength( uint64_t aValue ) + void SetPadDieLength( int64_t aValue ) { if( m_parent ) m_parent->SetPadDieLength( m_parent->GetPadDieLength() - m_pad_die_length + aValue ); @@ -257,7 +266,7 @@ public: m_pad_die_length = aValue; } - void AddPadDieLength( uint64_t aValue ) + void AddPadDieLength( int64_t aValue ) { if( m_parent ) m_parent->AddPadDieLength( aValue ); @@ -266,7 +275,7 @@ public: m_pad_die_length += aValue; } - void SubPadDieLength( uint64_t aValue ) + void SubPadDieLength( int64_t aValue ) { if( m_parent ) m_parent->SubPadDieLength( aValue ); @@ -334,10 +343,10 @@ private: NETINFO_ITEM* m_net = nullptr; unsigned int m_pad_count = 0; unsigned int m_via_count = 0; - uint64_t m_via_length = 0; - uint64_t m_pad_die_length = 0; + int64_t m_via_length = 0; + int64_t m_pad_die_length = 0; - std::map m_layer_wire_length{}; + std::map m_layer_wire_length{}; // Dirty bits to record when some attribute has changed, in order to avoid unnecessary sort // operations. @@ -514,7 +523,7 @@ public: } // Then add any netclass groups required by this item - if( m_parent.m_group_by_netclass && !groupMatched ) + if( m_parent.m_groupByNetclass && !groupMatched ) { LIST_ITEM_ITER groups_begin = m_items.begin(); LIST_ITEM_ITER groups_end = std::find_if_not( m_items.begin(), m_items.end(), @@ -544,7 +553,7 @@ public: return { new_iter }; } - void addItems( std::vector> aItems ) + void addItems( std::vector>& aItems ) { m_items.reserve( m_items.size() + aItems.size() ); @@ -569,7 +578,7 @@ public: { ItemChanged( wxDataViewItem( parent ) ); - if( m_parent.m_group_by_netclass && parent != nullptr && parent->ChildrenCount() == 0 ) + if( m_parent.m_groupByNetclass && parent != nullptr && parent->ChildrenCount() == 0 ) { auto p = std::find_if( m_items.begin(), m_items.end(), [&]( std::unique_ptr& x ) @@ -604,7 +613,7 @@ public: std::unique_ptr& group = m_items.emplace_back( std::make_unique( groupId, rule->GetPattern(), LIST_ITEM::GROUP_TYPE::USER_DEFINED ) ); m_custom_group_map[ rule->GetPattern() ] = group.get(); - group->SetLayerCount( m_parent.m_brd->GetCopperLayerCount() ); + group->SetLayerCount( m_parent.m_board->GetCopperLayerCount() ); ItemAdded( wxDataViewItem( group->Parent() ), wxDataViewItem( group.get() ) ); ++groupId; } @@ -750,7 +759,7 @@ protected: } } - static int compareUInt( uint64_t aValue1, uint64_t aValue2, bool aAsc ) + static int compareUInt( int64_t aValue1, int64_t aValue2, bool aAsc ) { if( aAsc ) return aValue1 < aValue2 ? -1 : 1; diff --git a/qa/data/pcbnew/length_calculations.kicad_dru b/qa/data/pcbnew/length_calculations.kicad_dru new file mode 100644 index 0000000000..8adaf60be1 --- /dev/null +++ b/qa/data/pcbnew/length_calculations.kicad_dru @@ -0,0 +1,31 @@ +(version 1) + +(rule "CASE_1" + (condition "A.hasNetclass('CASE_1')") + (constraint length (min 13.3345mm) (max 13.3555mm)) +) + +(rule "CASE_2" + (condition "A.hasNetclass('CASE_2')") + (constraint length (min 14.8795mm) (max 14.8805mm)) +) + +(rule "CASE_3" + (condition "A.hasNetclass('CASE_3')") + (constraint length (min 14.8795mm) (max 14.8805mm)) +) + +(rule "CASE_4" + (condition "A.hasNetclass('CASE_4')") + (constraint length (min 16.4245mm) (max 16.4250mm)) +) + +(rule "CASE_5" + (condition "A.hasNetclass('CASE_5')") + (constraint length (min 13.5470mm) (max 13.5480mm)) +) + +(rule "CASE_6" + (condition "A.hasNetclass('CASE_6')") + (constraint length (min 13.3345mm) (max 13.3555mm)) +) diff --git a/qa/data/pcbnew/length_calculations.kicad_pcb b/qa/data/pcbnew/length_calculations.kicad_pcb new file mode 100644 index 0000000000..55fb86952b --- /dev/null +++ b/qa/data/pcbnew/length_calculations.kicad_pcb @@ -0,0 +1,2971 @@ +(kicad_pcb + (version 20250324) + (generator "pcbnew") + (generator_version "9.99") + (general + (thickness 1.6) + (legacy_teardrops no) + ) + (paper "A4") + (layers + (0 "F.Cu" signal) + (2 "B.Cu" signal) + (9 "F.Adhes" user "F.Adhesive") + (11 "B.Adhes" user "B.Adhesive") + (13 "F.Paste" user) + (15 "B.Paste" user) + (5 "F.SilkS" user "F.Silkscreen") + (7 "B.SilkS" user "B.Silkscreen") + (1 "F.Mask" user) + (3 "B.Mask" user) + (17 "Dwgs.User" user "User.Drawings") + (19 "Cmts.User" user "User.Comments") + (21 "Eco1.User" user "User.Eco1") + (23 "Eco2.User" user "User.Eco2") + (25 "Edge.Cuts" user) + (27 "Margin" user) + (31 "F.CrtYd" user "F.Courtyard") + (29 "B.CrtYd" user "B.Courtyard") + (35 "F.Fab" user) + (33 "B.Fab" user) + (39 "User.1" user) + (41 "User.2" user) + (43 "User.3" user) + (45 "User.4" user) + ) + (setup + (stackup + (layer "F.SilkS" + (type "Top Silk Screen") + ) + (layer "F.Paste" + (type "Top Solder Paste") + ) + (layer "F.Mask" + (type "Top Solder Mask") + (thickness 0.01) + ) + (layer "F.Cu" + (type "copper") + (thickness 0.035) + ) + (layer "dielectric 1" + (type "core") + (thickness 1.51) + (material "FR4") + (epsilon_r 4.5) + (loss_tangent 0.02) + ) + (layer "B.Cu" + (type "copper") + (thickness 0.035) + ) + (layer "B.Mask" + (type "Bottom Solder Mask") + (thickness 0.01) + ) + (layer "B.Paste" + (type "Bottom Solder Paste") + ) + (layer "B.SilkS" + (type "Bottom Silk Screen") + ) + (copper_finish "None") + (dielectric_constraints no) + ) + (pad_to_mask_clearance 0) + (allow_soldermask_bridges_in_footprints no) + (tenting + (front yes) + (back yes) + ) + (covering + (front no) + (back no) + ) + (plugging + (front no) + (back no) + ) + (capping no) + (filling no) + (pcbplotparams + (layerselection 0x00000000_00000000_55555555_5755f5ff) + (plot_on_all_layers_selection 0x00000000_00000000_00000000_00000000) + (disableapertmacros no) + (usegerberextensions no) + (usegerberattributes yes) + (usegerberadvancedattributes yes) + (creategerberjobfile yes) + (dashed_line_dash_ratio 12.000000) + (dashed_line_gap_ratio 3.000000) + (svgprecision 4) + (plotframeref no) + (mode 1) + (useauxorigin no) + (hpglpennumber 1) + (hpglpenspeed 20) + (hpglpendiameter 15.000000) + (pdf_front_fp_property_popups yes) + (pdf_back_fp_property_popups yes) + (pdf_metadata yes) + (pdf_single_document no) + (dxfpolygonmode yes) + (dxfimperialunits yes) + (dxfusepcbnewfont yes) + (psnegative no) + (psa4output no) + (plot_black_and_white yes) + (sketchpadsonfab no) + (plotpadnumbers no) + (hidednponfab no) + (sketchdnponfab yes) + (crossoutdnponfab yes) + (subtractmaskfromsilk no) + (outputformat 1) + (mirror no) + (drillshape 1) + (scaleselection 1) + (outputdirectory "") + ) + ) + (net 0 "") + (net 1 "Net-(R1-Pad2)") + (net 2 "unconnected-(R1-Pad1)") + (net 3 "unconnected-(R2-Pad2)") + (net 4 "unconnected-(R3-Pad1)") + (net 5 "Net-(R3-Pad2)") + (net 6 "unconnected-(R4-Pad2)") + (net 7 "unconnected-(R5-Pad1)") + (net 8 "Net-(R5-Pad2)") + (net 9 "unconnected-(R6-Pad2)") + (net 10 "Net-(R7-Pad2)") + (net 11 "unconnected-(R7-Pad1)") + (net 12 "unconnected-(R8-Pad2)") + (net 13 "unconnected-(R9-Pad1)") + (net 14 "Net-(R10-Pad1)") + (net 15 "unconnected-(R10-Pad2)") + (net 16 "unconnected-(R11-Pad1)") + (net 17 "Net-(R11-Pad2)") + (net 18 "unconnected-(R12-Pad2)") + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "04ea2b22-d896-43cb-9c3a-1e66e8eb0847") + (at 121.3885 65.024) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R7" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "72cfeaa7-cc83-48e1-852e-ee1c952a4760") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "1fb399fa-3990-4ada-9646-61beb1af6ae7") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "20712705-3d62-4560-9da9-52b5306bb5f4") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "cb3fe137-9194-40bb-ac46-659caf5b3b74") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/56b08867-b16e-43c2-b207-b7d60b64724b") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "4e75f1de-04c4-495f-b76e-059858867c52") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "3283a683-b323-4139-980d-2bfb5cea236e") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "fc50115b-ec89-446d-a518-ae2c7632fd06") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "ae2cbb44-3d9b-4acd-8f1f-72cd9f05084c") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "cb5a2bb3-b6f4-47cd-ba2a-61b9de989632") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "7ee9a79e-2c55-4746-bf83-bc8edbd1d2c4") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "e895c7e7-5897-4485-bee6-1825c67eb6fe") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "f02f1e63-5efb-4b9a-983b-33c0951e735c") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "e99833ff-1064-4782-92fb-c04f1f9df53b") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "f7487a94-4758-4d06-81f3-8cc226d7a340") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "5ff47d06-60b4-4562-8543-b1edb2195d16") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 11 "unconnected-(R7-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "f67361a1-2642-499e-99b5-002bc8384376") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 10 "Net-(R7-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "10fcc8c1-3284-44ae-a341-1093963535e7") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "04f7c7ed-0693-4022-9c4b-9def71d5da1f") + (at 136.5485 59.817) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R6" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "2f2a15fc-b92d-46b1-8b97-0a01bad4463f") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "d4b7638c-739a-4cc0-bf7a-6f337bc47970") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "52990154-5e93-43af-82d1-352d215c8c6f") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "b8c8b3ec-6a41-4e04-998b-912c70c9c7fd") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/5bf2c0f9-3408-444a-b15c-da38a88dabb2") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "eccd4f99-de91-40f4-9f61-19f070af6c50") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "b971f627-0cba-4315-bd4a-8af17128be59") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "7072f8bd-913f-467d-91f4-9f7b2e366a90") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "b0f59e11-14a1-4455-8cc6-a70f3960eba5") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "5c1122dd-fa05-440b-a920-b3399f54d1af") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "4687813b-f7d7-464d-a0bc-294baf9a01ac") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "225a8081-b5cc-45f8-a731-f90c9a8ec89a") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "8ea525c6-4195-4914-85cf-d642319da59a") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "ccbc5976-3e59-4f40-a4ad-5105c1fc518f") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "b8f61de7-febf-4db4-ac5f-2ee0d17a8dad") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "398657c7-e16e-4a70-9701-896bc2704631") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 8 "Net-(R5-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "7a1ed77a-c115-49e0-a798-ec90c571e379") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 9 "unconnected-(R6-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "6ea0ad58-c22f-4a25-b4aa-7fbae7ea9083") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "529064d0-7e10-4d7b-a72c-d6b7fbc7392b") + (at 136.5485 54.229) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R4" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "13d8c2e5-e915-44fd-8781-ba925df9885c") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "d4ee03a9-06fa-4426-9f06-3ac23708c266") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "c95bf595-e69c-472b-8b38-81a35296d320") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "44ec66a0-d8df-4b07-a3af-a81e5fc3ab33") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/b145e0b0-6859-4129-abbc-9f01a0e7b6db") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "41b171b0-01a6-4959-b382-313ada322da5") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "fc2f8e72-bdfe-4e54-b946-673fce47f694") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "c793bfb9-9d59-4383-bb4b-d44aa4fae439") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "3818eb3c-8c57-4a09-a414-914633980005") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "d269592c-c3b0-4e84-b4ca-70566313d9cf") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "77893962-1c26-4fc9-8c90-8f4b4a0e08e3") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "cc268c4e-8e1a-43cb-bff1-f25c84b6a98c") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "397d5c2b-4d02-4da0-b3ea-4e7cf4aeee71") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "e9a8942c-9733-43e4-a9a7-563a5d1cab11") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "98e4816f-4308-4ced-a269-e97ccca7afd5") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "2fff1f1d-ad9c-46fd-a13f-65077cb5ae7c") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 5 "Net-(R3-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "b2b470b4-a101-48f5-bc49-aafda90f0480") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 6 "unconnected-(R4-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "0207ca97-d214-4f1b-9ae4-432d015074d0") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "5868271c-0257-4eca-8cea-1ee9e70d5d4c") + (at 136.5485 70.485) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R10" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "c1fa1a18-4172-4ae1-a51c-053bfabe0021") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "59d40043-fd0e-4bae-9377-a3f598ed4b94") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "c825028b-f4e6-441a-9579-42e2b07860d9") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "7195900c-9b1e-4ccb-8ced-f0f7a84aac80") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/79448150-99a5-4c94-ac27-52492ec93915") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "a479e8d7-7346-4c19-a175-a071c5b50065") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "32e5d6d7-291c-483c-8f6a-3d14e9fc6621") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "a2bbdea5-5c3f-4db9-99dc-75d673906cf7") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "f9154429-5ac8-4e76-b917-9a7175640a51") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "376f25aa-ceea-45bf-976c-dcd879fd8c41") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "3340f742-b965-4107-9bfd-460fc793804e") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "1db5b3f9-ef89-488f-964f-a8d78802664f") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "e51d69fe-633f-41d9-84c6-9e344639e0d1") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "2dbdd40d-b260-4387-ba1d-65675b256a58") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "dbaf447a-d99c-43d5-a706-a58d03a75511") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "8a782fba-179a-4103-8536-447c9d0c7255") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 14 "Net-(R10-Pad1)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "76d0d913-b563-4e43-b5f8-a3aacffe0a4f") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 15 "unconnected-(R10-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "a0285d41-0fca-4ce3-b511-b55001bc6523") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "71684e2d-ab0c-444b-baf7-ae104292d13d") + (at 121.3885 69.977) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R9" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "f7063b7b-06a1-468a-aab5-499845953ce9") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "d1ca100f-d624-43c6-8678-e2b103a75f3a") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "53fba311-0cea-4e91-bd06-cc2184893872") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "c7285b72-787c-46df-92bc-68a15a965a46") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/aca834eb-a675-4f4a-90b9-621f18ee31f2") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "71affa8c-359c-4d1e-b88f-269a37deb81b") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "eed9d8b2-eb3e-4561-ae0b-e4c642ae59f9") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "46b0b441-1e0f-45b4-9a9d-2c397945be18") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "18799ae5-b7af-479f-83f2-ce29eba9b766") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "07f4adab-277a-4f2a-92ff-1064a9e56e93") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "4be6b98a-6184-4494-8db0-fc00ab899c6e") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "6ac4882f-91cd-4f39-af42-a9848da53c84") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "8e94549c-10ce-4fe9-a640-5f40db270451") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "4483a171-5833-4de0-83d2-b9a211a9863c") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "c1c7e678-97cd-4958-8b6e-510ac8359782") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "dcea1120-ec53-4fb0-a1e1-a0474a645918") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 13 "unconnected-(R9-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "29e36af3-8b8b-498f-a104-879c6aaaec07") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 14 "Net-(R10-Pad1)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "380fd19a-cf30-4b21-95ac-64d21b76e634") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "b330f043-6e57-41b3-bd1c-9cb844d6d769") + (at 136.5485 65.024) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R8" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "cfeba9e1-5bd9-4156-ad5d-b89c4108b38b") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "c8414768-2236-4859-a678-824b8e86c5e6") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "43874fb7-f6fa-4bc2-a184-041ae55e561c") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "a61405e1-74eb-4d3d-9d2b-ca3f1b1f63c1") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/7a67fd78-6ba4-466b-84ae-f8b310434b7d") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "f31ecdb2-40c7-4429-9737-b55471c37d52") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "e71e4819-2f33-4ed9-a457-fdeb404f4442") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "eacbe1f5-bef2-4da1-972c-38268090beaa") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "1f3bcc6c-3be4-45cb-b274-726f85b9364a") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "73dbd4c7-4e22-42da-a212-04a9eda9db5a") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "ce08944b-00d7-43d4-8236-a05fbb080b54") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "7b15f0a6-9ab0-453b-8f2c-2a4621800f90") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "2cf41172-a7ce-4e41-ac6a-fb4ad4b5c924") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "4b9a08ec-b803-4edb-b6ae-e24acf0d9e21") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "023e5964-6d72-470c-bbc7-a6eb31b330a5") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "79e209a4-79a0-4a8f-ab2b-f9c50c7cd256") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 10 "Net-(R7-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "515a76e9-582f-4819-8adb-0b08de175e40") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 12 "unconnected-(R8-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "af29e4c8-605a-4974-bd83-1714414300fa") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "bfaa1742-674a-4410-8f8a-6abc55652f0a") + (at 136.5485 75.438) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R12" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "8c25f626-451f-4da5-b66c-f197f4b56116") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "8a376daf-9b8f-46c4-ad7e-ae9f73880a25") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "fea8a07a-e63d-44b7-b567-fde09bdd572b") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "17dd7208-8212-4423-afc4-8ea9bbe37ac9") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/83cf7517-0908-4f43-8186-847b43fc6fe2") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "30bb36e4-b515-4f28-b078-c0de7eab84ac") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "dfab54d2-beb0-458c-9b6a-91498366427d") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "d1d7aedc-f1d6-4239-8a45-43e40bfb50ec") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "baf0dd29-63aa-4d49-84c5-23b693501c89") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "e174ae61-0eab-4a10-9830-449563a901a3") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "fa33bbc1-f496-438f-aea4-763de7023729") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "8f01b453-935e-44e1-aca3-517ec1b77e2a") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "54c673c8-d73f-4ec7-ab5e-5751ff8a1ae7") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "69843604-1776-4080-bb4c-3b75d27c14a9") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "22a9c72f-eafc-492e-b6c7-0344e42ee753") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "0e03ae4f-d78d-4d58-8e14-ca2b222e39e8") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 17 "Net-(R11-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "2cd6b45a-840c-4dc0-9f76-8f3cf7b5a779") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 18 "unconnected-(R12-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "5910a855-8a92-4b02-8015-6432250318a4") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "cc73c760-da3c-4207-8ffd-8a8ba3d0bd4d") + (at 136.5485 48.895) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R2" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "658818dd-5231-48e2-85eb-bb396bb62f31") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "a7932fe2-0055-4a14-98b4-be94e629d78b") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "a040aa87-22cd-4623-a585-c00d1226e760") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "a44e87df-1120-4813-aba0-bb1ea3daa83f") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/b49ae0c1-db1a-41f4-8250-37c8a4120d6a") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "b616f7f0-13c0-4872-af4e-f21769b3ae52") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "e9f4a72a-5d37-4050-899e-ff66ea35ffc0") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "e496bbc7-cac2-4441-b7a5-4ed09400f31a") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "8bc1b1c4-18d1-43fb-bc9a-cf70b2c50adf") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "4d0ee6f2-1979-40c1-9d01-fbedfbfb3b5b") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "f6952cc5-f34a-4176-a634-1d88cf2251d0") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "f503cb48-38b8-44f6-b979-0893afae9abb") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "62bb3024-cdfc-4062-92e4-54d2195b6ad8") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "9b109114-11ee-42f3-886c-f97b5c999fd6") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "1de583d1-31a2-4a66-9985-27b96a0424a8") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "c3dca618-80e5-4e76-b454-9e291201c0ce") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 1 "Net-(R1-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "a42a3a2b-d552-40d1-a8a9-a002b0edce0b") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 3 "unconnected-(R2-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "3a71dca1-94f1-4caf-b220-2609aa056fb8") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "df6b175f-26bd-42bd-bf0e-d928246ad926") + (at 121.3885 48.895) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R1" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "f18b461c-7b62-4d55-bd2e-744ec0e4a4d4") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "9deb1b71-9e70-4d7d-ab81-8492cf6f046d") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "8abff99d-f27e-4864-b5bb-6507904c082a") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "9aeee373-0418-4cc3-83f7-19d202f63fe6") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/d813b923-8c78-4eb2-9135-15fe3af259c1") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "c7ec9aee-1c1c-4666-8c7b-6dfd22aeebbb") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "465ccdd3-07d7-44ef-b19e-a33b03e61f77") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "67c42d86-ce45-43dc-8508-d2a500d4261a") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "5e83f7c7-62fe-4021-9e7a-67dc48e6b0e1") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "a1b58625-17b5-423e-89e7-253b00e7fcc6") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "6362cd1f-6fc4-46ec-b1cd-f1b947aa8dcb") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "46e8c56e-ea0d-449a-a0e3-f83ad403eb8f") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "a5e84d5a-e701-4f4d-8e87-8bdaf8f2d69c") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "757127ba-d45a-46a3-97ba-7aea2d42410a") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "680073c4-954b-49c6-9ca4-0fccfc74c230") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "020041a6-53a8-4710-9e7f-7b4309a05c00") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 2 "unconnected-(R1-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "39a4747f-900d-4c3d-a54f-b919dd2c12a0") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 1 "Net-(R1-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "015941d9-6323-4746-884e-1c2e00370a90") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "ff9a7bc6-9a7a-4e19-ab71-43384ebe9056") + (at 121.3885 75.438) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R11" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "0bc1c4e8-6578-4b68-8a4e-43ea7872590d") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "9b7d9bfa-6380-4e3f-aa81-b7556a89b790") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "866ac6a3-07d6-454a-bbf5-19e1aa6e08ad") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (unlocked yes) + (layer "F.Fab") + (hide yes) + (uuid "e6d23510-f8a4-4077-ae12-dff9df0593ff") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/01b8b62f-a02d-47b6-913f-ba6e4cec9d42") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "6d5a8f21-efa4-47c4-a9cc-0ef510c87392") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "680de25e-22e2-4f0c-961a-9c3f0027e9f2") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "5eb0c997-d7d5-4534-9e43-d69251bd0141") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "9a6e01e1-fcf1-4b10-843c-3a51da2a3d13") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "55ba96e1-266e-4335-9fbe-2b39028dced4") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "e6faf690-1324-4175-ae7f-70263d7bd7dc") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "380fa069-1918-450a-b34c-0f59ffe13490") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "35fcc90b-9ebd-4dce-9852-e0e9a97c641f") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "3c0a0f50-ceb8-46aa-99b3-05f47bb01cc2") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "e8e6252a-08fd-4c82-ad05-293fbc73f8fe") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "b32b08af-6760-4fe9-a181-381c23b7ac01") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 16 "unconnected-(R11-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "d9fe8a7f-f1d5-490a-9bdb-c8a5a2c2c28f") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 17 "Net-(R11-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "ddc647a4-156c-4284-b689-03ed9b7f5429") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "B.Cu") + (uuid "57a0cfc3-2e69-4f72-86c2-842a58a704c8") + (at 121.3885 59.817) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R5" + (at 0 1.65 0) + (layer "B.SilkS") + (uuid "43ffe203-4adb-427d-bd40-5330fa1f04b0") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Value" "R" + (at 0 -1.65 0) + (layer "B.Fab") + (uuid "1570cb2f-a19c-4715-b71f-16a6453a9bd8") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Datasheet" "" + (at 0 0 180) + (unlocked yes) + (layer "B.Fab") + (hide yes) + (uuid "65149973-ccfe-437f-b505-31c5f3eb7943") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Description" "Resistor" + (at 0 0 180) + (unlocked yes) + (layer "B.Fab") + (hide yes) + (uuid "2ee82552-cbdb-4596-958a-89cc63ad9fb6") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property ki_fp_filters "R_*") + (path "/d757d628-b3f5-4761-8175-3953ab6a18f0") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "8d462200-990d-4f2d-abf2-3d8e48d03e20") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "52df51ed-d7df-4812-9b55-2b0f0cd704f7") + ) + (fp_line + (start -1.68 -0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "745a7ff8-a3f6-473c-b7f0-bbbe69a3efa2") + ) + (fp_line + (start -1.68 0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "a0ebf16e-7113-4c9e-853f-ee5d84124d95") + ) + (fp_line + (start 1.68 -0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "1b1a68e2-0531-488d-89ec-3c4d9419c867") + ) + (fp_line + (start 1.68 0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "98d78dfe-135e-4457-b469-f1252f2551e7") + ) + (fp_line + (start -1 -0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "e373163b-fed2-4380-9960-f99eb08bedc2") + ) + (fp_line + (start -1 0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "ca7c8e3f-442e-4e64-a329-93ecadb1f4ff") + ) + (fp_line + (start 1 -0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "5a64717c-5bdf-4bc6-9ae0-c8232e8fc7f7") + ) + (fp_line + (start 1 0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "d51b532c-7106-4b3c-ae9d-3aabef33c2fe") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "B.Fab") + (uuid "63e9a225-0292-4f34-9558-beb7c9095ae4") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + (justify mirror) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 7 "unconnected-(R5-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "2430e15c-b676-4c4e-9e34-c5d880f0731b") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 8 "Net-(R5-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "ac6d5dbc-cf73-4bac-b084-917cbb4ad9a9") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "B.Cu") + (uuid "7ddd92b9-2566-4f1e-a460-86985bbca2f7") + (at 121.3885 54.229) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R3" + (at 0 1.65 0) + (layer "B.SilkS") + (uuid "ccbf728e-5352-4e0d-b3cf-7d6293ccacf8") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Value" "R" + (at 0 -1.65 0) + (layer "B.Fab") + (uuid "3e371d8c-f1f2-4939-a8b4-f7a9affa0dd0") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Datasheet" "" + (at 0 0 180) + (unlocked yes) + (layer "B.Fab") + (hide yes) + (uuid "14a4e4ed-f00c-435a-a29b-0e6de39fced5") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Description" "Resistor" + (at 0 0 180) + (unlocked yes) + (layer "B.Fab") + (hide yes) + (uuid "85bd32cc-8ba5-4614-b9a8-08e555310172") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property ki_fp_filters "R_*") + (path "/03b93256-daf2-4509-b2e3-b35dbd891ffa") + (sheetname "/") + (sheetfile "length_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "62d1e7c3-5e53-4b44-bae3-3169ec1890eb") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "dd7b5251-2782-4aa3-81cd-12ff288cb6c9") + ) + (fp_line + (start -1.68 -0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "eb95bbad-1957-420e-b737-244fdec61f40") + ) + (fp_line + (start -1.68 0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "31798277-3284-4164-bf41-6deebcbdca0b") + ) + (fp_line + (start 1.68 -0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "917bd8d7-718c-4d90-9931-11854a0e67a9") + ) + (fp_line + (start 1.68 0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "721a9d94-e273-4fde-bbaa-56d98abd98dd") + ) + (fp_line + (start -1 -0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "4356ad0c-5232-4eeb-86f6-611a28a42c70") + ) + (fp_line + (start -1 0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "68694e90-ee8b-45b6-9155-cbfa3a7bfa6d") + ) + (fp_line + (start 1 -0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "c1ece85e-bc2e-4cd5-bb67-2f7a35ecb412") + ) + (fp_line + (start 1 0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "b3a7cba3-acf0-43c2-b644-4d4818df1b73") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "B.Fab") + (uuid "713f9ab1-cc8a-4b7b-809f-cc733110a6d5") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + (justify mirror) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 4 "unconnected-(R3-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "1ac4daa7-8b86-4380-8cf5-c1fd883cfaae") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 5 "Net-(R3-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "2c609249-3271-4c00-bf46-08e5e16141dc") + ) + (embedded_fonts no) + (model "${KICAD8_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (gr_rect + (start 117.983 44.831) + (end 139.827 78.867) + (stroke + (width 0.05) + (type default) + ) + (fill no) + (layer "Edge.Cuts") + (uuid "c76ab917-b23d-4e7f-9834-95032daf41f7") + ) + (gr_text "Single track from pad to pad.\nLength 13.3350mm." + (at 140.335 49.784 0) + (layer "User.1") + (uuid "596dac34-72b5-41c2-becc-a11c9ab0504c") + (effects + (font + (size 0.7 0.7) + (thickness 0.15) + ) + (justify left bottom) + ) + ) + (gr_text "Track from pad to pad with extra track-in-pad requiring electrical optimisation.\nRaw lengths: 13.6942mm\nOptimised length: 13.5475mm" + (at 140.335 71.374 0) + (layer "User.1") + (uuid "6448468c-14e3-4794-849d-b94aceda806f") + (effects + (font + (size 0.7 0.7) + (thickness 0.15) + ) + (justify left bottom) + ) + ) + (gr_text "Single track from pad to pad, with stub pad in via.\nLength 13.3350mm (13.3350mm track, 0mm via)" + (at 140.462 76.581 0) + (layer "User.1") + (uuid "70dca8e7-5e31-4135-acd4-b347f6685bdb") + (effects + (font + (size 0.7 0.7) + (thickness 0.15) + ) + (justify left bottom) + ) + ) + (gr_text "Single track from pad to pad, with pad in via.\nLength 14.880mm (13.3350mm track, 1.545mm via)" + (at 140.335 55.118 0) + (layer "User.1") + (uuid "7f83c8bc-048a-4517-931d-402bdaf6d0dd") + (effects + (font + (size 0.7 0.7) + (thickness 0.15) + ) + (justify left bottom) + ) + ) + (gr_text "Track from pad to pad with two vias in track.\nLength 16.4250mm (13.3350mm track, 3.0900mm via)" + (at 140.335 66.04 0) + (layer "User.1") + (uuid "f5fbb9e1-572a-4383-ab51-2db44f23ce1d") + (effects + (font + (size 0.7 0.7) + (thickness 0.15) + ) + (justify left bottom) + ) + ) + (gr_text "Track from pad to pad with via in track.\nLength 14.880mm (13.3350mm track, 1.545mm via)" + (at 140.335 60.706 0) + (layer "User.1") + (uuid "f95e887a-6964-4b75-a74b-933d6fa74a59") + (effects + (font + (size 0.7 0.7) + (thickness 0.15) + ) + (justify left bottom) + ) + ) + (segment + (start 135.636 48.895) + (end 122.301 48.895) + (width 0.2) + (layer "F.Cu") + (net 1) + (uuid "9f743250-a887-46af-aed6-2fd45db6a7e1") + ) + (via + (at 135.636 54.229) + (size 0.6) + (drill 0.3) + (layers "F.Cu" "B.Cu") + (tenting + (front none) + (back none) + ) + (capping none) + (covering + (front none) + (back none) + ) + (plugging + (front none) + (back none) + ) + (filling none) + (net 5) + (uuid "f4c1fcab-5457-4b15-983a-8f12c21ef45e") + ) + (segment + (start 122.301 54.229) + (end 135.636 54.229) + (width 0.2) + (layer "B.Cu") + (net 5) + (uuid "7882056d-9400-4fc9-9398-f6b6904c34d9") + ) + (segment + (start 128.524 59.817) + (end 135.636 59.817) + (width 0.2) + (layer "F.Cu") + (net 8) + (uuid "73f765a3-0ae7-4bb1-b6ec-511b1a1249b8") + ) + (via + (at 128.524 59.817) + (size 0.6) + (drill 0.3) + (layers "F.Cu" "B.Cu") + (tenting + (front none) + (back none) + ) + (capping none) + (covering + (front none) + (back none) + ) + (plugging + (front none) + (back none) + ) + (filling none) + (net 8) + (uuid "8352b634-86e7-47f7-b258-6b7048589d90") + ) + (segment + (start 122.301 59.817) + (end 128.524 59.817) + (width 0.2) + (layer "B.Cu") + (net 8) + (uuid "035866bb-17ed-4bef-9da0-0e6aaf97074d") + ) + (segment + (start 130.556 65.024) + (end 135.636 65.024) + (width 0.2) + (layer "F.Cu") + (net 10) + (uuid "684e4aa4-c6d3-4402-a4ac-94b966e9d3de") + ) + (segment + (start 122.301 65.024) + (end 125.984 65.024) + (width 0.2) + (layer "F.Cu") + (net 10) + (uuid "8eff2ee7-e31c-41a7-b376-2d9ba3730595") + ) + (via + (at 125.984 65.024) + (size 0.6) + (drill 0.3) + (layers "F.Cu" "B.Cu") + (tenting + (front none) + (back none) + ) + (capping none) + (covering + (front none) + (back none) + ) + (plugging + (front none) + (back none) + ) + (filling none) + (net 10) + (uuid "184f4538-1c2f-4927-bbdd-56676a443e14") + ) + (via + (at 130.556 65.024) + (size 0.6) + (drill 0.3) + (layers "F.Cu" "B.Cu") + (tenting + (front none) + (back none) + ) + (capping none) + (covering + (front none) + (back none) + ) + (plugging + (front none) + (back none) + ) + (filling none) + (net 10) + (uuid "3fef3305-7954-42cd-b1c6-3e572ccb6ebd") + ) + (segment + (start 125.984 65.024) + (end 130.556 65.024) + (width 0.2) + (layer "B.Cu") + (net 10) + (uuid "d3b54b30-466d-4557-a68e-a57415a0167d") + ) + (segment + (start 135.382 69.977) + (end 122.301 69.977) + (width 0.2) + (layer "F.Cu") + (net 14) + (uuid "43312f5d-7d1a-4c8e-a89c-74ecdec351df") + ) + (segment + (start 135.636 70.231) + (end 135.382 69.977) + (width 0.2) + (layer "F.Cu") + (net 14) + (uuid "542f6995-dd88-43f6-9cb8-cebec562958f") + ) + (segment + (start 135.636 70.485) + (end 135.636 70.231) + (width 0.2) + (layer "F.Cu") + (net 14) + (uuid "61a8d5de-9cd9-4536-bbc9-572b5e532ed3") + ) + (segment + (start 122.301 75.438) + (end 129.159 75.438) + (width 0.2) + (layer "F.Cu") + (net 17) + (uuid "dbab810b-9ce6-4a30-9062-7eba8fd80ed3") + ) + (segment + (start 129.159 75.438) + (end 135.636 75.438) + (width 0.2) + (layer "F.Cu") + (net 17) + (uuid "dc4ee856-10e1-41b5-ae74-f1dd8548be2b") + ) + (via + (at 129.159 75.438) + (size 0.6) + (drill 0.3) + (layers "F.Cu" "B.Cu") + (tenting + (front none) + (back none) + ) + (capping none) + (covering + (front none) + (back none) + ) + (plugging + (front none) + (back none) + ) + (filling none) + (net 17) + (uuid "2933b31e-1101-4f9c-8ac5-c157771bc6f0") + ) + (embedded_fonts no) +) diff --git a/qa/data/pcbnew/length_calculations.kicad_pro b/qa/data/pcbnew/length_calculations.kicad_pro new file mode 100644 index 0000000000..4ccbdeefeb --- /dev/null +++ b/qa/data/pcbnew/length_calculations.kicad_pro @@ -0,0 +1,658 @@ +{ + "board": { + "3dviewports": [], + "design_settings": { + "defaults": { + "apply_defaults_to_fp_fields": false, + "apply_defaults_to_fp_shapes": false, + "apply_defaults_to_fp_text": false, + "board_outline_line_width": 0.05, + "copper_line_width": 0.2, + "copper_text_italic": false, + "copper_text_size_h": 1.5, + "copper_text_size_v": 1.5, + "copper_text_thickness": 0.3, + "copper_text_upright": false, + "courtyard_line_width": 0.05, + "dimension_precision": 4, + "dimension_units": 3, + "dimensions": { + "arrow_length": 1270000, + "extension_offset": 500000, + "keep_text_aligned": true, + "suppress_zeroes": true, + "text_position": 0, + "units_format": 0 + }, + "fab_line_width": 0.1, + "fab_text_italic": false, + "fab_text_size_h": 1.0, + "fab_text_size_v": 1.0, + "fab_text_thickness": 0.15, + "fab_text_upright": false, + "other_line_width": 0.1, + "other_text_italic": false, + "other_text_size_h": 1.0, + "other_text_size_v": 1.0, + "other_text_thickness": 0.15, + "other_text_upright": false, + "pads": { + "drill": 0.8, + "height": 1.27, + "width": 2.54 + }, + "silk_line_width": 0.1, + "silk_text_italic": false, + "silk_text_size_h": 1.0, + "silk_text_size_v": 1.0, + "silk_text_thickness": 0.1, + "silk_text_upright": false, + "zones": { + "min_clearance": 0.5 + } + }, + "diff_pair_dimensions": [], + "drc_exclusions": [], + "meta": { + "version": 2 + }, + "rule_severities": { + "annular_width": "error", + "clearance": "error", + "connection_width": "warning", + "copper_edge_clearance": "error", + "copper_sliver": "warning", + "courtyards_overlap": "error", + "creepage": "error", + "diff_pair_gap_out_of_range": "error", + "diff_pair_uncoupled_length_too_long": "error", + "drill_out_of_range": "error", + "duplicate_footprints": "warning", + "extra_footprint": "warning", + "footprint": "error", + "footprint_filters_mismatch": "ignore", + "footprint_symbol_mismatch": "warning", + "footprint_type_mismatch": "ignore", + "hole_clearance": "error", + "hole_to_hole": "warning", + "holes_co_located": "warning", + "invalid_outline": "error", + "isolated_copper": "warning", + "item_on_disabled_layer": "error", + "items_not_allowed": "error", + "length_out_of_range": "error", + "lib_footprint_issues": "warning", + "lib_footprint_mismatch": "warning", + "malformed_courtyard": "error", + "microvia_drill_out_of_range": "error", + "mirrored_text_on_front_layer": "warning", + "missing_courtyard": "ignore", + "missing_footprint": "warning", + "net_conflict": "warning", + "nonmirrored_text_on_back_layer": "warning", + "npth_inside_courtyard": "ignore", + "padstack": "warning", + "pth_inside_courtyard": "ignore", + "shorting_items": "error", + "silk_edge_clearance": "warning", + "silk_over_copper": "warning", + "silk_overlap": "warning", + "skew_out_of_range": "error", + "solder_mask_bridge": "error", + "starved_thermal": "error", + "text_height": "warning", + "text_on_edge_cuts": "error", + "text_thickness": "warning", + "through_hole_pad_without_hole": "error", + "too_many_vias": "error", + "track_angle": "error", + "track_dangling": "warning", + "track_segment_length": "error", + "track_width": "error", + "tracks_crossing": "error", + "unconnected_items": "error", + "unresolved_variable": "error", + "via_dangling": "warning", + "zones_intersect": "error" + }, + "rules": { + "max_error": 0.005, + "min_clearance": 0.0, + "min_connection": 0.0, + "min_copper_edge_clearance": 0.5, + "min_groove_width": 0.0, + "min_hole_clearance": 0.25, + "min_hole_to_hole": 0.25, + "min_microvia_diameter": 0.2, + "min_microvia_drill": 0.1, + "min_resolved_spokes": 2, + "min_silk_clearance": 0.0, + "min_text_height": 0.8, + "min_text_thickness": 0.08, + "min_through_hole_diameter": 0.3, + "min_track_width": 0.0, + "min_via_annular_width": 0.1, + "min_via_diameter": 0.5, + "solder_mask_to_copper_clearance": 0.0, + "use_height_for_length_calcs": true + }, + "teardrop_options": [ + { + "td_onpthpad": true, + "td_onroundshapesonly": false, + "td_onsmdpad": true, + "td_ontrackend": false, + "td_onvia": true + } + ], + "teardrop_parameters": [ + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_round_shape", + "td_width_to_size_filter_ratio": 0.9 + }, + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_rect_shape", + "td_width_to_size_filter_ratio": 0.9 + }, + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_track_end", + "td_width_to_size_filter_ratio": 0.9 + } + ], + "track_widths": [], + "tuning_pattern_settings": { + "diff_pair_defaults": { + "corner_radius_percentage": 80, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.2, + "single_sided": false, + "spacing": 1.0 + }, + "diff_pair_skew_defaults": { + "corner_radius_percentage": 80, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.2, + "single_sided": false, + "spacing": 0.6 + }, + "single_track_defaults": { + "corner_radius_percentage": 80, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.2, + "single_sided": false, + "spacing": 0.6 + } + }, + "via_dimensions": [], + "zones_allow_external_fillets": false + }, + "ipc2581": { + "dist": "", + "distpn": "", + "internal_id": "", + "mfg": "", + "mpn": "" + }, + "layer_pairs": [], + "layer_presets": [], + "viewports": [] + }, + "boards": [], + "component_class_settings": { + "assignments": [], + "meta": { + "version": 0 + }, + "sheet_component_classes": { + "enabled": false + } + }, + "cvpcb": { + "equivalence_files": [] + }, + "erc": { + "erc_exclusions": [], + "meta": { + "version": 0 + }, + "pin_map": [ + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2 + ], + [ + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2 + ], + [ + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2 + ], + [ + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 2 + ], + [ + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2 + ], + [ + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2 + ], + [ + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2 + ] + ], + "rule_severities": { + "bus_definition_conflict": "error", + "bus_entry_needed": "error", + "bus_to_bus_conflict": "error", + "bus_to_net_conflict": "error", + "different_unit_footprint": "error", + "different_unit_net": "error", + "duplicate_reference": "error", + "duplicate_sheet_names": "error", + "endpoint_off_grid": "warning", + "extra_units": "error", + "footprint_filter": "ignore", + "footprint_link_issues": "warning", + "four_way_junction": "ignore", + "global_label_dangling": "warning", + "hier_label_mismatch": "error", + "label_dangling": "error", + "label_multiple_wires": "warning", + "lib_symbol_issues": "warning", + "lib_symbol_mismatch": "warning", + "missing_bidi_pin": "warning", + "missing_input_pin": "warning", + "missing_power_pin": "error", + "missing_unit": "warning", + "multiple_net_names": "warning", + "net_not_bus_member": "warning", + "no_connect_connected": "warning", + "no_connect_dangling": "warning", + "pin_not_connected": "error", + "pin_not_driven": "error", + "pin_to_pin": "warning", + "power_pin_not_driven": "error", + "same_local_global_label": "warning", + "similar_label_and_power": "warning", + "similar_labels": "warning", + "similar_power": "warning", + "simulation_model_issue": "ignore", + "single_global_label": "ignore", + "unannotated": "error", + "unconnected_wire_endpoint": "warning", + "unit_value_mismatch": "error", + "unresolved_variable": "error", + "wire_dangling": "error" + } + }, + "libraries": { + "pinned_footprint_libs": [], + "pinned_symbol_libs": [] + }, + "meta": { + "filename": "length_calculations.kicad_pro", + "version": 3 + }, + "net_settings": { + "classes": [ + { + "bus_width": 12, + "clearance": 0.2, + "diff_pair_gap": 0.25, + "diff_pair_via_gap": 0.25, + "diff_pair_width": 0.2, + "line_style": 0, + "microvia_diameter": 0.3, + "microvia_drill": 0.1, + "name": "Default", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 2147483647, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "track_width": 0.2, + "via_diameter": 0.6, + "via_drill": 0.3, + "wire_width": 6 + } + ], + "meta": { + "version": 4 + }, + "net_colors": null, + "netclass_assignments": { + "Net-(R1-Pad2)": [ + "CASE_1" + ], + "Net-(R10-Pad1)": [ + "CASE_5" + ], + "Net-(R11-Pad2)": [ + "CASE_6" + ], + "Net-(R3-Pad2)": [ + "CASE_2" + ], + "Net-(R5-Pad2)": [ + "CASE_3" + ], + "Net-(R7-Pad2)": [ + "CASE_4" + ] + }, + "netclass_patterns": [] + }, + "pcbnew": { + "last_paths": { + "gencad": "", + "idf": "", + "netlist": "", + "plot": "", + "pos_files": "", + "specctra_dsn": "", + "step": "", + "svg": "", + "vrml": "" + }, + "page_layout_descr_file": "" + }, + "schematic": { + "annotate_start_num": 0, + "bom_export_filename": "${PROJECTNAME}.csv", + "bom_fmt_presets": [], + "bom_fmt_settings": { + "field_delimiter": ",", + "keep_line_breaks": false, + "keep_tabs": false, + "name": "CSV", + "ref_delimiter": ",", + "ref_range_delimiter": "", + "string_delimiter": "\"" + }, + "bom_presets": [], + "bom_settings": { + "exclude_dnp": false, + "fields_ordered": [ + { + "group_by": false, + "label": "Reference", + "name": "Reference", + "show": true + }, + { + "group_by": true, + "label": "Value", + "name": "Value", + "show": true + }, + { + "group_by": true, + "label": "Footprint", + "name": "Footprint", + "show": true + }, + { + "group_by": false, + "label": "Datasheet", + "name": "Datasheet", + "show": true + }, + { + "group_by": false, + "label": "Description", + "name": "Description", + "show": false + }, + { + "group_by": false, + "label": "Qty", + "name": "${QUANTITY}", + "show": true + }, + { + "group_by": false, + "label": "#", + "name": "${ITEM_NUMBER}", + "show": false + }, + { + "group_by": true, + "label": "DNP", + "name": "${DNP}", + "show": true + }, + { + "group_by": true, + "label": "Exclude from BOM", + "name": "${EXCLUDE_FROM_BOM}", + "show": true + }, + { + "group_by": true, + "label": "Exclude from Board", + "name": "${EXCLUDE_FROM_BOARD}", + "show": true + } + ], + "filter_string": "", + "group_symbols": true, + "include_excluded_from_bom": true, + "name": "", + "sort_asc": true, + "sort_field": "Reference" + }, + "connection_grid_size": 50.0, + "drawing": { + "dashed_lines_dash_length_ratio": 12.0, + "dashed_lines_gap_length_ratio": 3.0, + "default_line_thickness": 6.0, + "default_text_size": 50.0, + "field_names": [], + "intersheets_ref_own_page": false, + "intersheets_ref_prefix": "", + "intersheets_ref_short": false, + "intersheets_ref_show": false, + "intersheets_ref_suffix": "", + "junction_size_choice": 3, + "label_size_ratio": 0.375, + "operating_point_overlay_i_precision": 3, + "operating_point_overlay_i_range": "~A", + "operating_point_overlay_v_precision": 3, + "operating_point_overlay_v_range": "~V", + "overbar_offset_ratio": 1.23, + "pin_symbol_size": 25.0, + "text_offset_ratio": 0.15 + }, + "legacy_lib_dir": "", + "legacy_lib_list": [], + "meta": { + "version": 1 + }, + "net_format_name": "", + "page_layout_descr_file": "", + "plot_directory": "", + "space_save_all_events": true, + "spice_current_sheet_as_root": false, + "spice_external_command": "spice \"%I\"", + "spice_model_current_sheet_as_root": true, + "spice_save_all_currents": false, + "spice_save_all_dissipations": false, + "spice_save_all_voltages": false, + "subpart_first_id": 65, + "subpart_id_separator": 0 + }, + "sheets": [ + [ + "a4e4d485-017a-4720-8992-147a6425c6a8", + "Root" + ] + ], + "text_variables": {} +} diff --git a/qa/data/pcbnew/length_calculations.kicad_sch b/qa/data/pcbnew/length_calculations.kicad_sch new file mode 100644 index 0000000000..9a3ec1e8ff --- /dev/null +++ b/qa/data/pcbnew/length_calculations.kicad_sch @@ -0,0 +1,1340 @@ +(kicad_sch + (version 20250318) + (generator "eeschema") + (generator_version "9.99") + (uuid "a4e4d485-017a-4720-8992-147a6425c6a8") + (paper "A4") + (lib_symbols + (symbol "Device:R" + (pin_numbers + (hide yes) + ) + (pin_names + (offset 0) + ) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (duplicate_pin_numbers_are_jumpers no) + (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) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "ki_keywords" "R res resistor" + (at 0 0 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "ki_fp_filters" "R_*" + (at 0 0 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (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) + ) + ) + ) + ) + ) + (embedded_fonts no) + ) + ) + (no_connect + (at 104.14 62.23) + (uuid "0127d9a4-092e-4061-b48e-dba257a794fc") + ) + (no_connect + (at 143.51 62.23) + (uuid "1b6a40fa-5c43-4ba0-8d75-535e44bd6baf") + ) + (no_connect + (at 104.14 45.72) + (uuid "2aa3a3d8-922c-4424-9674-ad3020d54f45") + ) + (no_connect + (at 69.85 95.25) + (uuid "4ddf989c-92fe-41a4-a617-2d1f77cf446f") + ) + (no_connect + (at 143.51 45.72) + (uuid "51135b82-884e-4428-82d4-5690e94f0d7a") + ) + (no_connect + (at 69.85 78.74) + (uuid "67619533-0698-44e3-b112-788ee12817d2") + ) + (no_connect + (at 109.22 62.23) + (uuid "9a93065c-d0bb-45db-b785-a0c085450bdd") + ) + (no_connect + (at 69.85 45.72) + (uuid "a28bb316-a7d2-4d88-8069-0ea77c7346a3") + ) + (no_connect + (at 109.22 45.72) + (uuid "d18c3e5a-6060-4d28-96b6-3d46f8911911") + ) + (no_connect + (at 69.85 62.23) + (uuid "f101f51f-a0af-4dc6-9b4a-ea582b6e6fca") + ) + (no_connect + (at 104.14 78.74) + (uuid "fd25da23-8f83-4762-9f3d-7cd4ec2488de") + ) + (no_connect + (at 104.14 95.25) + (uuid "fdad69da-3897-4b91-980b-abedc2adec51") + ) + (wire + (pts + (xy 77.47 95.25) (xy 96.52 95.25) + ) + (stroke + (width 0) + (type default) + ) + (uuid "2e83a8dd-8f0d-47ab-a545-da722e18a313") + ) + (wire + (pts + (xy 116.84 62.23) (xy 135.89 62.23) + ) + (stroke + (width 0) + (type default) + ) + (uuid "32e1327f-91c3-4857-8f12-162dea49b44f") + ) + (wire + (pts + (xy 116.84 45.72) (xy 135.89 45.72) + ) + (stroke + (width 0) + (type default) + ) + (uuid "6b1f3bf5-933a-488b-a177-feb48427633e") + ) + (wire + (pts + (xy 77.47 45.72) (xy 96.52 45.72) + ) + (stroke + (width 0) + (type default) + ) + (uuid "b27349f9-21a5-4015-bd8f-677969b93c35") + ) + (wire + (pts + (xy 77.47 78.74) (xy 96.52 78.74) + ) + (stroke + (width 0) + (type default) + ) + (uuid "de02d4f3-72eb-45a7-a9ed-9134bd661421") + ) + (wire + (pts + (xy 77.47 62.23) (xy 96.52 62.23) + ) + (stroke + (width 0) + (type default) + ) + (uuid "e2eaf332-20d3-42a6-b0e8-b93dc409d912") + ) + (rule_area + (polyline + (pts + (xy 78.74 99.06) (xy 95.25 99.06) (xy 95.25 87.63) (xy 78.74 87.63) + ) + (stroke + (width 0) + (type dash) + ) + (fill + (type none) + ) + (uuid 00eecfca-4355-468a-8f8a-0a09cb29f99a) + ) + ) + (rule_area + (polyline + (pts + (xy 118.11 66.04) (xy 134.62 66.04) (xy 134.62 54.61) (xy 118.11 54.61) + ) + (stroke + (width 0) + (type dash) + ) + (fill + (type none) + ) + (uuid 32da8b36-cb1f-4a9a-85d8-d1afdc4898aa) + ) + ) + (rule_area + (polyline + (pts + (xy 118.11 49.53) (xy 134.62 49.53) (xy 134.62 38.1) (xy 118.11 38.1) + ) + (stroke + (width 0) + (type dash) + ) + (fill + (type none) + ) + (uuid a24add76-7dfd-4444-9dda-fcc7d11e90f7) + ) + ) + (rule_area + (polyline + (pts + (xy 78.74 49.53) (xy 95.25 49.53) (xy 95.25 38.1) (xy 78.74 38.1) + ) + (stroke + (width 0) + (type dash) + ) + (fill + (type none) + ) + (uuid a65fbffa-06a0-4827-99ce-ea7b4a63e94a) + ) + ) + (rule_area + (polyline + (pts + (xy 78.74 66.04) (xy 95.25 66.04) (xy 95.25 54.61) (xy 78.74 54.61) + ) + (stroke + (width 0) + (type dash) + ) + (fill + (type none) + ) + (uuid c1e370d6-2d8f-4805-a267-0c31677d862e) + ) + ) + (rule_area + (polyline + (pts + (xy 78.74 82.55) (xy 95.25 82.55) (xy 95.25 71.12) (xy 78.74 71.12) + ) + (stroke + (width 0) + (type dash) + ) + (fill + (type none) + ) + (uuid fc51baa0-4911-4162-81ad-46922827a963) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 119.38 38.1 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "24bca6e4-43ea-406f-9cb9-237e61748b1b") + (property "Net Class" "CASE_5" + (at 120.0785 35.56 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -50.8 -5.08 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 80.01 71.12 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "510a234c-fa16-4f57-9a7b-932bd9eed9d1") + (property "Net Class" "CASE_3" + (at 80.7085 68.58 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -90.17 27.94 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 80.01 54.61 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "57e685ae-a5cc-4c0f-a270-0fcd84286c66") + (property "Net Class" "CASE_2" + (at 80.7085 52.07 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -90.17 11.43 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 119.38 54.61 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "baaa924c-8b71-44bb-8f27-cb582d094be5") + (property "Net Class" "CASE_6" + (at 120.0785 52.07 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -50.8 11.43 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 80.01 87.63 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "df406bef-0003-4530-b436-69c587aee978") + (property "Net Class" "CASE_4" + (at 80.7085 85.09 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -90.17 44.45 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 80.01 38.1 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "e9f323da-b3f0-4995-8219-1d41cd955bc5") + (property "Net Class" "CASE_1" + (at 80.7085 35.56 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -90.17 -5.08 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 113.03 62.23 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "01b8b62f-a02d-47b6-913f-ba6e4cec9d42") + (property "Reference" "R11" + (at 113.03 55.88 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 113.03 58.42 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 113.03 64.008 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 113.03 62.23 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 113.03 62.23 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "2e9079b9-46a8-48bb-b039-f4df0d6500dd") + ) + (pin "2" + (uuid "45143a4c-357e-4048-856c-d6f22014e66b") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R11") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 73.66 62.23 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "03b93256-daf2-4509-b2e3-b35dbd891ffa") + (property "Reference" "R3" + (at 73.66 55.88 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 73.66 58.42 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 73.66 64.008 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 73.66 62.23 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 73.66 62.23 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "98a010c7-5aaa-4f75-bf6d-4b10147fa17b") + ) + (pin "2" + (uuid "22db3346-f33c-4540-bceb-1718fb374850") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R3") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 73.66 95.25 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "56b08867-b16e-43c2-b207-b7d60b64724b") + (property "Reference" "R7" + (at 73.66 88.9 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 73.66 91.44 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 73.66 97.028 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 73.66 95.25 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 73.66 95.25 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "910e995d-d0a1-42be-be1c-5b962f9b0270") + ) + (pin "2" + (uuid "2464db33-0a6d-4873-9b83-bbd0b911694c") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R7") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 100.33 78.74 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "5bf2c0f9-3408-444a-b15c-da38a88dabb2") + (property "Reference" "R6" + (at 100.33 72.39 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 100.33 74.93 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 100.33 80.518 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 100.33 78.74 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 100.33 78.74 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "d051ed8f-5535-44b3-8179-28ed637a36bf") + ) + (pin "2" + (uuid "2335b1d3-ddcf-4e84-810d-03179b96b222") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R6") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 139.7 45.72 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "79448150-99a5-4c94-ac27-52492ec93915") + (property "Reference" "R10" + (at 139.7 39.37 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 139.7 41.91 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 139.7 47.498 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 139.7 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 139.7 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "ddc90c83-aea9-4178-9faa-f13127d1adc0") + ) + (pin "2" + (uuid "e3188596-152f-45c4-9183-f218113f9f4b") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R10") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 100.33 95.25 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "7a67fd78-6ba4-466b-84ae-f8b310434b7d") + (property "Reference" "R8" + (at 100.33 88.9 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 100.33 91.44 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 100.33 97.028 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 100.33 95.25 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 100.33 95.25 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "48fe2024-7889-4f51-882a-ec045680aaee") + ) + (pin "2" + (uuid "c229208e-16e4-433f-b832-62a20a8a6300") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R8") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 139.7 62.23 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "83cf7517-0908-4f43-8186-847b43fc6fe2") + (property "Reference" "R12" + (at 139.7 55.88 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 139.7 58.42 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 139.7 64.008 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 139.7 62.23 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 139.7 62.23 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "738e5a60-c78e-4dc6-9408-54a65990f441") + ) + (pin "2" + (uuid "bdc5a3f7-3204-4787-b58e-ffc1a4aed6a2") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R12") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 113.03 45.72 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "aca834eb-a675-4f4a-90b9-621f18ee31f2") + (property "Reference" "R9" + (at 113.03 39.37 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 113.03 41.91 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 113.03 47.498 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 113.03 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 113.03 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "a05886b6-1ae1-470a-b33c-9fcbdadb9a46") + ) + (pin "2" + (uuid "fab8e581-38b9-449d-95ff-fc9ef9a280e3") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R9") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 100.33 62.23 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "b145e0b0-6859-4129-abbc-9f01a0e7b6db") + (property "Reference" "R4" + (at 100.33 55.88 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 100.33 58.42 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 100.33 64.008 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 100.33 62.23 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 100.33 62.23 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "78d1353e-06ca-4b7c-ac11-5b9cf13c55f0") + ) + (pin "2" + (uuid "bf15e74d-40e7-4da0-87a3-47ebf3d31a72") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R4") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 100.33 45.72 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "b49ae0c1-db1a-41f4-8250-37c8a4120d6a") + (property "Reference" "R2" + (at 100.33 39.37 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 100.33 41.91 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 100.33 47.498 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 100.33 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 100.33 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "0b5a9a14-b352-4796-83be-bf83dae06280") + ) + (pin "2" + (uuid "2b60b290-2fbc-4ee3-9ef7-35aa7f91ecfe") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R2") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 73.66 78.74 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "d757d628-b3f5-4761-8175-3953ab6a18f0") + (property "Reference" "R5" + (at 73.66 72.39 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 73.66 74.93 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 73.66 80.518 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 73.66 78.74 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 73.66 78.74 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "44d3fc5b-9b1a-4bd1-9f29-8696844f4ce2") + ) + (pin "2" + (uuid "4d142bae-a16e-4b7e-b869-48b681965fc7") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R5") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 73.66 45.72 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "d813b923-8c78-4eb2-9135-15fe3af259c1") + (property "Reference" "R1" + (at 73.66 39.37 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 73.66 41.91 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 73.66 47.498 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 73.66 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 73.66 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "40c43150-18de-4705-92b1-0fd7fa1237c5") + ) + (pin "2" + (uuid "e527d82d-a8a5-42b3-9378-a836a0cc6673") + ) + (instances + (project "length_calculations" + (path "/a4e4d485-017a-4720-8992-147a6425c6a8" + (reference "R1") + (unit 1) + ) + ) + ) + ) + (sheet_instances + (path "/" + (page "1") + ) + ) + (embedded_fonts no) +) diff --git a/qa/tests/pcbnew/CMakeLists.txt b/qa/tests/pcbnew/CMakeLists.txt index 885560d997..02e9f954d0 100644 --- a/qa/tests/pcbnew/CMakeLists.txt +++ b/qa/tests/pcbnew/CMakeLists.txt @@ -68,6 +68,7 @@ set( QA_PCBNEW_SRCS drc/test_drc_incorrect_text_mirror.cpp drc/test_drc_starved_thermal.cpp drc/test_drc_orientation.cpp + drc/test_drc_lengths.cpp pcb_io/altium/test_altium_rule_transformer.cpp pcb_io/altium/test_altium_pcblib_import.cpp diff --git a/qa/tests/pcbnew/drc/test_drc_lengths.cpp b/qa/tests/pcbnew/drc/test_drc_lengths.cpp new file mode 100644 index 0000000000..d6a4335b19 --- /dev/null +++ b/qa/tests/pcbnew/drc/test_drc_lengths.cpp @@ -0,0 +1,108 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct DRC_REGRESSION_TEST_FIXTURE +{ + DRC_REGRESSION_TEST_FIXTURE() : m_settingsManager( true /* headless */ ) {} + + SETTINGS_MANAGER m_settingsManager; + std::unique_ptr m_board; +}; + + +BOOST_FIXTURE_TEST_CASE( DRCLengths, DRC_REGRESSION_TEST_FIXTURE ) +{ + // Check for minimum copper connection errors + + std::vector> tests = { + { "length_calculations", 0 } // Exclude warnings on unconnected pads + }; + + for( const std::pair& test : tests ) + { + KI_TEST::LoadBoard( m_settingsManager, test.first, m_board ); + KI_TEST::FillZones( m_board.get() ); + + std::vector violations; + BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); + + // Disable DRC tests not useful or not handled in this testcase + bds.m_DRCSeverities[DRCE_INVALID_OUTLINE] = SEVERITY::RPT_SEVERITY_IGNORE; + bds.m_DRCSeverities[DRCE_UNCONNECTED_ITEMS] = SEVERITY::RPT_SEVERITY_IGNORE; + bds.m_DRCSeverities[DRCE_COPPER_SLIVER] = SEVERITY::RPT_SEVERITY_IGNORE; + bds.m_DRCSeverities[DRCE_STARVED_THERMAL] = SEVERITY::RPT_SEVERITY_IGNORE; + bds.m_DRCSeverities[DRCE_DRILL_OUT_OF_RANGE] = SEVERITY::RPT_SEVERITY_IGNORE; + bds.m_DRCSeverities[DRCE_VIA_DIAMETER] = SEVERITY::RPT_SEVERITY_IGNORE; + // These DRC tests are not useful and do not work because they need a footprint library + // associated to the board + bds.m_DRCSeverities[DRCE_LIB_FOOTPRINT_ISSUES] = SEVERITY::RPT_SEVERITY_IGNORE; + bds.m_DRCSeverities[DRCE_LIB_FOOTPRINT_MISMATCH] = SEVERITY::RPT_SEVERITY_IGNORE; + bds.m_DRCSeverities[DRCE_DANGLING_VIA] = SEVERITY::RPT_SEVERITY_IGNORE; + + // Ensure that our desired error is fired + bds.m_DRCSeverities[DRCE_LENGTH_OUT_OF_RANGE] = SEVERITY::RPT_SEVERITY_ERROR; + + bds.m_DRCEngine->SetViolationHandler( + [&]( const std::shared_ptr& aItem, VECTOR2I aPos, int aLayer, + DRC_CUSTOM_MARKER_HANDLER* aCustomHandler ) + { + if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR ) + violations.push_back( *aItem ); + } ); + + bds.m_DRCEngine->RunTests( EDA_UNITS::MM, true, false ); + + if( violations.size() == test.second ) + { + BOOST_CHECK_EQUAL( 1, 1 ); // quiet "did not check any assertions" warning + BOOST_TEST_MESSAGE( wxString::Format( "DRC lengths: %s, passed", test.first ) ); + } + else + { + UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::INCH ); + + std::map itemMap; + m_board->FillItemMap( itemMap ); + + for( const DRC_ITEM& item : violations ) + { + BOOST_TEST_MESSAGE( item.ShowReport( &unitsProvider, RPT_SEVERITY_ERROR, itemMap ) ); + } + + BOOST_ERROR( wxString::Format( "DRC skew: %s, failed (violations found %d expected %d)", test.first, + (int) violations.size(), test.second ) ); + } + } +} diff --git a/qa/tools/pns/pns_log_viewer_frame.h b/qa/tools/pns/pns_log_viewer_frame.h index 352ef4d919..a869e825dd 100644 --- a/qa/tools/pns/pns_log_viewer_frame.h +++ b/qa/tools/pns/pns_log_viewer_frame.h @@ -28,10 +28,12 @@ #ifndef __PNS_LOG_VIEWER_FRAME_H #define __PNS_LOG_VIEWER_FRAME_H +#include #include #include #include #include +#include #include "pns_log_file.h" #include "pns_log_player.h" @@ -105,6 +107,58 @@ public: return ( aLayer / 2 ) - 1; } + long long int CalculateRoutedPathLength( const PNS::ITEM_SET& aLine, const PNS::SOLID* aStartPad, + const PNS::SOLID* aEndPad ) override + { + std::vector lengthItems; + + for( int idx = 0; idx < aLine.Size(); idx++ ) + { + const PNS::ITEM* lineItem = aLine[idx]; + + if( const PNS::LINE* l = dyn_cast( lineItem ) ) + { + LENGTH_CALCULATION_ITEM item; + item.SetLine( l->CLine() ); + + const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() ); + item.SetLayers( layer ); + + lengthItems.emplace_back( std::move( item ) ); + } + else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 ) + { + const int layerPrev = aLine[idx - 1]->Layer(); + const int layerNext = aLine[idx + 1]->Layer(); + const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev ); + const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext ); + + if( layerPrev != layerNext ) + { + LENGTH_CALCULATION_ITEM item; + item.SetVia( static_cast( lineItem->GetSourceItem() ) ); + item.SetLayers( pcbLayerPrev, pcbLayerNext ); + lengthItems.emplace_back( std::move( item ) ); + } + } + } + + const PAD* startPad = nullptr; + const PAD* endPad = nullptr; + + if( aStartPad ) + startPad = static_cast( aStartPad->Parent() ); + + if( aEndPad ) + endPad = static_cast( aEndPad->Parent() ); + + constexpr PATH_OPTIMISATIONS opts = { + .OptimiseViaLayers = false, .MergeTracks = false, .OptimiseTracesInPads = false, .InferViaInPad = true + }; + + return m_board->GetLengthCalculation()->CalculateLength( lengthItems, opts, startPad, endPad ); + } + private: std::shared_ptr m_board; };