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 int AnchorCount() const;
|
||||||
virtual const VECTOR2I GetAnchor( int n ) 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
|
int Net() const
|
||||||
{
|
{
|
||||||
return ( !m_parent || !m_valid ) ? -1 : m_parent->GetNetCode();
|
return ( !m_parent || !m_valid ) ? -1 : m_parent->GetNetCode();
|
||||||
|
@ -343,6 +346,20 @@ public:
|
||||||
virtual int AnchorCount() const override;
|
virtual int AnchorCount() const override;
|
||||||
virtual const VECTOR2I GetAnchor( int n ) 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
|
bool Collide( SHAPE* aRefShape ) const
|
||||||
{
|
{
|
||||||
BOX2I bbox = aRefShape->BBox();
|
BOX2I bbox = aRefShape->BBox();
|
||||||
|
@ -368,7 +385,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<VECTOR2I> m_testOutlinePoints;
|
|
||||||
int m_subpolyIndex;
|
int m_subpolyIndex;
|
||||||
PCB_LAYER_ID m_layer;
|
PCB_LAYER_ID m_layer;
|
||||||
std::shared_ptr<SHAPE_POLY_SET> m_triangulatedPoly;
|
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()
|
void RN_NET::Update()
|
||||||
{
|
{
|
||||||
compute();
|
compute();
|
||||||
|
|
||||||
|
#ifdef PROFILE
|
||||||
|
PROF_TIMER cnt( "optimize" );
|
||||||
|
#endif
|
||||||
|
optimizeRNEdges();
|
||||||
|
#ifdef PROFILE
|
||||||
|
cnt.Show();
|
||||||
|
#endif
|
||||||
|
|
||||||
m_dirty = false;
|
m_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,4 +567,3 @@ bool RN_NET::NearestBicoloredPair( const RN_NET& aOtherNet, VECTOR2I* aPos1, VEC
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,11 @@ protected:
|
||||||
///< Compute the minimum spanning tree using Kruskal's algorithm
|
///< Compute the minimum spanning tree using Kruskal's algorithm
|
||||||
void kruskalMST( const std::vector<CN_EDGE> &aEdges );
|
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
|
///< Vector of nodes
|
||||||
std::multiset<std::shared_ptr<CN_ANCHOR>, CN_PTR_CMP> m_nodes;
|
std::multiset<std::shared_ptr<CN_ANCHOR>, CN_PTR_CMP> m_nodes;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue