Optimize ratsnest line endings for zones.
This commit is contained in:
parent
01572c0f7d
commit
f095453d3e
|
@ -250,6 +250,9 @@ public:
|
|||
virtual int AnchorCount() const;
|
||||
virtual const VECTOR2I GetAnchor( int n ) const;
|
||||
|
||||
int GetAnchorItemCount() const { return m_anchors.size(); }
|
||||
std::shared_ptr<CN_ANCHOR> GetAnchorItem( int n ) const { return m_anchors[n]; }
|
||||
|
||||
int Net() const
|
||||
{
|
||||
return ( !m_parent || !m_valid ) ? -1 : m_parent->GetNetCode();
|
||||
|
@ -343,6 +346,20 @@ public:
|
|||
virtual int AnchorCount() const override;
|
||||
virtual const VECTOR2I GetAnchor( int n ) const override;
|
||||
|
||||
const SHAPE_LINE_CHAIN& GetOutline() const
|
||||
{
|
||||
return m_triangulatedPoly->Outline( m_subpolyIndex );
|
||||
}
|
||||
|
||||
VECTOR2I ClosestPoint( const VECTOR2I aPt )
|
||||
{
|
||||
VECTOR2I closest;
|
||||
|
||||
m_triangulatedPoly->SquaredDistanceToPolygon( aPt, m_subpolyIndex, &closest );
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
bool Collide( SHAPE* aRefShape ) const
|
||||
{
|
||||
BOX2I bbox = aRefShape->BBox();
|
||||
|
@ -368,7 +385,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
std::vector<VECTOR2I> m_testOutlinePoints;
|
||||
int m_subpolyIndex;
|
||||
PCB_LAYER_ID m_layer;
|
||||
std::shared_ptr<SHAPE_POLY_SET> m_triangulatedPoly;
|
||||
|
|
|
@ -328,11 +328,127 @@ void RN_NET::compute()
|
|||
}
|
||||
|
||||
|
||||
void RN_NET::optimizeRNEdges()
|
||||
{
|
||||
auto findZoneAnchor =
|
||||
[&]( const VECTOR2I& aPos, const LSET& aLayerSet,
|
||||
const std::shared_ptr<CN_ANCHOR> aAnchor )
|
||||
{
|
||||
SEG::ecoord closest_dist_sq = ( aAnchor->Pos() - aPos ).SquaredEuclideanNorm();
|
||||
VECTOR2I closest_pt;
|
||||
CN_ITEM* closest_item = nullptr;
|
||||
|
||||
for( CN_ITEM* item : aAnchor->Item()->ConnectedItems() )
|
||||
{
|
||||
CN_ZONE_LAYER* zoneLayer = dynamic_cast<CN_ZONE_LAYER*>( item );
|
||||
|
||||
if( zoneLayer && aLayerSet.test( zoneLayer->Layer() ) )
|
||||
{
|
||||
const std::vector<VECTOR2I>& pts = zoneLayer->GetOutline().CPoints();
|
||||
|
||||
for( VECTOR2I pt : pts )
|
||||
{
|
||||
SEG::ecoord dist_sq = ( pt - aPos ).SquaredEuclideanNorm();
|
||||
|
||||
if( dist_sq < closest_dist_sq )
|
||||
{
|
||||
closest_pt = pt;
|
||||
closest_item = zoneLayer;
|
||||
closest_dist_sq = dist_sq;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( closest_item )
|
||||
{
|
||||
closest_item->AddAnchor( closest_pt );
|
||||
return closest_item->GetAnchorItem( closest_item->GetAnchorItemCount() - 1 );
|
||||
}
|
||||
|
||||
return aAnchor;
|
||||
};
|
||||
|
||||
auto findZoneToZoneAnchors =
|
||||
[&]( std::shared_ptr<CN_ANCHOR>& a, std::shared_ptr<CN_ANCHOR>& b )
|
||||
{
|
||||
for( CN_ITEM* itemA : a->Item()->ConnectedItems() )
|
||||
{
|
||||
CN_ZONE_LAYER* zoneLayerA = dynamic_cast<CN_ZONE_LAYER*>( itemA );
|
||||
|
||||
if( !zoneLayerA )
|
||||
continue;
|
||||
|
||||
for( CN_ITEM* itemB : b->Item()->ConnectedItems() )
|
||||
{
|
||||
CN_ZONE_LAYER* zoneLayerB = dynamic_cast<CN_ZONE_LAYER*>( itemB );
|
||||
|
||||
if( zoneLayerB && zoneLayerB->Layer() == zoneLayerA->Layer() )
|
||||
{
|
||||
// Process the first matching layer. We don't really care if it's
|
||||
// the "best" layer or not, as anything will be better than the
|
||||
// original anchors (which are connected to the zone and so certainly
|
||||
// don't look like they should have ratsnest lines coming off them).
|
||||
|
||||
VECTOR2I startA = zoneLayerA->GetOutline().GetPoint( 0 );
|
||||
VECTOR2I startB = zoneLayerB->GetOutline().GetPoint( 0 );
|
||||
const SHAPE* shapeA = &zoneLayerA->GetOutline();
|
||||
const SHAPE* shapeB = &zoneLayerB->GetOutline();
|
||||
int startDist = ( startA - startB ).EuclideanNorm();
|
||||
|
||||
VECTOR2I ptA;
|
||||
shapeA->Collide( shapeB, startDist + 10, nullptr, &ptA );
|
||||
zoneLayerA->AddAnchor( ptA );
|
||||
a = zoneLayerA->GetAnchorItem( zoneLayerA->GetAnchorItemCount() - 1 );
|
||||
|
||||
VECTOR2I ptB;
|
||||
shapeB->Collide( shapeA, startDist + 10, nullptr, &ptB );
|
||||
zoneLayerB->AddAnchor( ptB );
|
||||
b = zoneLayerB->GetAnchorItem( zoneLayerB->GetAnchorItemCount() - 1 );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for( CN_EDGE& edge : m_rnEdges )
|
||||
{
|
||||
std::shared_ptr<CN_ANCHOR> source = edge.GetSourceNode();
|
||||
std::shared_ptr<CN_ANCHOR> target = edge.GetTargetNode();
|
||||
|
||||
if( source->ConnectedItemsCount() == 0 )
|
||||
{
|
||||
edge.SetTargetNode( findZoneAnchor( source->Pos(), source->Parent()->GetLayerSet(),
|
||||
target ) );
|
||||
}
|
||||
else if( target->ConnectedItemsCount() == 0 )
|
||||
{
|
||||
edge.SetSourceNode( findZoneAnchor( target->Pos(), target->Parent()->GetLayerSet(),
|
||||
source ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
findZoneToZoneAnchors( source, target );
|
||||
edge.SetSourceNode( source );
|
||||
edge.SetTargetNode( target );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RN_NET::Update()
|
||||
{
|
||||
compute();
|
||||
|
||||
#ifdef PROFILE
|
||||
PROF_TIMER cnt( "optimize" );
|
||||
#endif
|
||||
optimizeRNEdges();
|
||||
#ifdef PROFILE
|
||||
cnt.Show();
|
||||
#endif
|
||||
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
|
@ -451,4 +567,3 @@ bool RN_NET::NearestBicoloredPair( const RN_NET& aOtherNet, VECTOR2I* aPos1, VEC
|
|||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -99,6 +99,11 @@ protected:
|
|||
///< Compute the minimum spanning tree using Kruskal's algorithm
|
||||
void kruskalMST( const std::vector<CN_EDGE> &aEdges );
|
||||
|
||||
///< Find optimal ends of RNEdges. The MST will have found the closest anchors, but when
|
||||
///< zones are involved we might have points closer than the anchors.
|
||||
void optimizeRNEdges();
|
||||
|
||||
protected:
|
||||
///< Vector of nodes
|
||||
std::multiset<std::shared_ptr<CN_ANCHOR>, CN_PTR_CMP> m_nodes;
|
||||
|
||||
|
|
Loading…
Reference in New Issue