Strict-order points in connection_width
The connection width checker uses morton codes to order elements. The sort should be primarily morton-based but needs to be stable in order to ensure that nextZ/prevZ elements are properly placed as the actual next/prev elements in the list. Otherwise, hitting a fracture point might make us skip in the wrong direction Fixes https://gitlab.com/kicad/code/kicad/issues/12831
This commit is contained in:
parent
7d2f83ea29
commit
b5bd633625
|
@ -252,7 +252,10 @@ private:
|
||||||
|
|
||||||
std::sort( queue.begin(), queue.end(), []( const Vertex* a, const Vertex* b )
|
std::sort( queue.begin(), queue.end(), []( const Vertex* a, const Vertex* b )
|
||||||
{
|
{
|
||||||
return a->z < b->z;
|
return a->z < b->z || ( a->z == b->z
|
||||||
|
&& ( ( a->x < b->x )
|
||||||
|
|| ( a->y < b->y )
|
||||||
|
|| ( a->i < b->i ) ) );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
Vertex* prev_elem = nullptr;
|
Vertex* prev_elem = nullptr;
|
||||||
|
@ -309,39 +312,15 @@ private:
|
||||||
return x | ( y << 1 );
|
return x | ( y << 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
constexpr bool same_point( const Vertex* aA, const Vertex* aB ) const
|
||||||
* Checks to see if there is a "substantial" protrusion in each polygon produced by the cut from
|
|
||||||
* aA to aB. Substantial in this case means that the polygon bulges out to a wider cross-section
|
|
||||||
* than the distance from aA to aB
|
|
||||||
* @param aA Starting point in the polygon
|
|
||||||
* @param aB Ending point in the polygon
|
|
||||||
* @return True if the two polygons are both "substantial"
|
|
||||||
*/
|
|
||||||
bool isSubstantial( Vertex* aA, Vertex* aB ) const
|
|
||||||
{
|
{
|
||||||
// `directions` is a bitfield where
|
return aA && aB && aA->x == aB->x && aA->y == aB->y;
|
||||||
// bit 0 = pos y
|
}
|
||||||
// bit 1 = neg y
|
|
||||||
// bit 2 = pos x
|
|
||||||
// bit 3 = neg x
|
|
||||||
// So, once directions = 15, we have all directions
|
|
||||||
int directions = 0;
|
|
||||||
|
|
||||||
// This is a failsafe in case of invalid lists. Never check
|
Vertex* getNextOutlineVertex( const Vertex* aPt ) const
|
||||||
// more than the total number of points in m_vertices
|
{
|
||||||
size_t checked = 0;
|
Vertex* nz = aPt->nextZ;
|
||||||
size_t total_pts = m_vertices.size();
|
Vertex* pz = aPt->prevZ;
|
||||||
|
|
||||||
Vertex* p0 = aA;
|
|
||||||
Vertex* p;
|
|
||||||
Vertex* nz = p0->nextZ;
|
|
||||||
Vertex* pz = p0->prevZ;
|
|
||||||
|
|
||||||
auto same_point =
|
|
||||||
[]( const Vertex* a, const Vertex* b ) -> bool
|
|
||||||
{
|
|
||||||
return a && b && a->x == b->x && a->y == b->y;
|
|
||||||
};
|
|
||||||
|
|
||||||
// If we hit a fracture point, we want to continue around the
|
// If we hit a fracture point, we want to continue around the
|
||||||
// edge we are working on and not switch to the pair edge
|
// edge we are working on and not switch to the pair edge
|
||||||
|
@ -350,22 +329,76 @@ private:
|
||||||
// a new fracture point, then we know that we are proceeding
|
// a new fracture point, then we know that we are proceeding
|
||||||
// in the wrong direction from the fracture and should
|
// in the wrong direction from the fracture and should
|
||||||
// fall through to the next point
|
// fall through to the next point
|
||||||
if( same_point( p0, nz )
|
if( same_point( aPt, nz )
|
||||||
&& !( same_point( nz->next, nz->next->prevZ ) || same_point( nz->next, nz->next->nextZ ) ) )
|
&& !( same_point( nz->next, nz->next->prevZ ) || same_point( nz->next, nz->next->nextZ ) ) )
|
||||||
{
|
{
|
||||||
p = nz->next;
|
return nz->next;
|
||||||
}
|
}
|
||||||
else if( same_point( p0, pz )
|
else if( same_point( aPt, pz )
|
||||||
&& !( same_point( pz->next, pz->next->prevZ ) || same_point( pz->next, pz->next->nextZ ) ) )
|
&& !( same_point( pz->next, pz->next->prevZ ) || same_point( pz->next, pz->next->nextZ ) ) )
|
||||||
{
|
{
|
||||||
p = pz->next;
|
return pz->next;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p = p0->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while( p0 != aB && checked < total_pts && directions != 0b1111 )
|
return aPt->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex* getPrevOutlineVertex( const Vertex* aPt ) const
|
||||||
|
{
|
||||||
|
Vertex* nz = aPt->nextZ;
|
||||||
|
Vertex* pz = aPt->prevZ;
|
||||||
|
|
||||||
|
// If we hit a fracture point, we want to continue around the
|
||||||
|
// edge we are working on and not switch to the pair edge
|
||||||
|
// However, this will depend on which direction the initial
|
||||||
|
// fracture hit is. If we find that we skip directly to
|
||||||
|
// a new fracture point, then we know that we are proceeding
|
||||||
|
// in the wrong direction from the fracture and should
|
||||||
|
// fall through to the next point
|
||||||
|
if( same_point( aPt, nz )
|
||||||
|
&& !( same_point( nz->prev, nz->prev->nextZ ) || same_point( nz->prev, nz->prev->prevZ ) ) )
|
||||||
|
{
|
||||||
|
return nz->prev;
|
||||||
|
}
|
||||||
|
else if( same_point( aPt, pz )
|
||||||
|
&& !( same_point( pz->prev, pz->prev->nextZ ) || same_point( pz->prev, pz->prev->prevZ ) ) )
|
||||||
|
{
|
||||||
|
return pz->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return aPt->prev;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if there is a "substantial" protrusion in each polygon produced by the cut from
|
||||||
|
* aA to aB. Substantial in this case means that the polygon bulges out to a wider cross-section
|
||||||
|
* than the distance from aA to aB
|
||||||
|
* @param aA Starting point in the polygon
|
||||||
|
* @param aB Ending point in the polygon
|
||||||
|
* @return True if the two polygons are both "substantial"
|
||||||
|
*/
|
||||||
|
bool isSubstantial( const Vertex* aA, const Vertex* aB ) const
|
||||||
|
{
|
||||||
|
// `directions` is a bitfield where
|
||||||
|
// bit 0 = pos y
|
||||||
|
// bit 1 = neg y
|
||||||
|
// bit 2 = pos x
|
||||||
|
// bit 3 = neg x
|
||||||
|
// So, once directions = 15, we have all directions
|
||||||
|
int directions = 0;
|
||||||
|
constexpr int all_dirs = 0b1111;
|
||||||
|
|
||||||
|
// This is a failsafe in case of invalid lists. Never check
|
||||||
|
// more than the total number of points in m_vertices
|
||||||
|
size_t checked = 0;
|
||||||
|
size_t total_pts = m_vertices.size();
|
||||||
|
|
||||||
|
const Vertex* p0 = aA;
|
||||||
|
const Vertex* p = getNextOutlineVertex( p0 );
|
||||||
|
|
||||||
|
|
||||||
|
while( !same_point( p0, aB ) && checked < total_pts && directions != all_dirs )
|
||||||
{
|
{
|
||||||
double diff_x = std::abs( p->x - p0->x );
|
double diff_x = std::abs( p->x - p0->x );
|
||||||
double diff_y = std::abs( p->y - p0->y );
|
double diff_y = std::abs( p->y - p0->y );
|
||||||
|
@ -396,32 +429,16 @@ private:
|
||||||
|
|
||||||
wxCHECK_MSG( checked < total_pts, false, wxT( "Invalid polygon detected. Missing points to check" ) );
|
wxCHECK_MSG( checked < total_pts, false, wxT( "Invalid polygon detected. Missing points to check" ) );
|
||||||
|
|
||||||
if( directions != 15 )
|
if( directions != all_dirs )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
p0 = aA;
|
p0 = aA;
|
||||||
nz = p0->nextZ;
|
p = getPrevOutlineVertex( p0 );
|
||||||
pz = p0->prevZ;
|
|
||||||
|
|
||||||
if( nz && same_point( p0, nz )
|
|
||||||
&& !( same_point( nz->prev, nz->prev->nextZ ) || same_point( nz->prev, nz->prev->prevZ ) ) )
|
|
||||||
{
|
|
||||||
p = nz->prev;
|
|
||||||
}
|
|
||||||
else if( pz && same_point( p0, pz )
|
|
||||||
&& !( same_point( pz->prev, pz->prev->nextZ ) || same_point( pz->prev, pz->prev->prevZ ) ) )
|
|
||||||
{
|
|
||||||
p = pz->prev;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p = p0->prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
directions = 0;
|
directions = 0;
|
||||||
checked = 0;
|
checked = 0;
|
||||||
|
|
||||||
while( p0 != aB && checked < total_pts && directions != 0b1111 )
|
while( !same_point( p0, aB ) && checked < total_pts && directions != all_dirs )
|
||||||
{
|
{
|
||||||
double diff_x = std::abs( p->x - p0->x );
|
double diff_x = std::abs( p->x - p0->x );
|
||||||
double diff_y = std::abs( p->y - p0->y );
|
double diff_y = std::abs( p->y - p0->y );
|
||||||
|
@ -452,7 +469,7 @@ private:
|
||||||
|
|
||||||
wxCHECK_MSG( checked < total_pts, false, wxT( "Invalid polygon detected. Missing points to check" ) );
|
wxCHECK_MSG( checked < total_pts, false, wxT( "Invalid polygon detected. Missing points to check" ) );
|
||||||
|
|
||||||
return ( directions == 15 );
|
return ( directions == all_dirs );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -564,10 +581,13 @@ private:
|
||||||
*/
|
*/
|
||||||
bool locallyInside( const Vertex* a, const Vertex* b ) const
|
bool locallyInside( const Vertex* a, const Vertex* b ) const
|
||||||
{
|
{
|
||||||
if( area( a->prev, a, a->next ) < 0 )
|
const Vertex* an = getNextOutlineVertex( a );
|
||||||
return area( a, b, a->next ) >= 0 && area( a, a->prev, b ) >= 0;
|
const Vertex* ap = getPrevOutlineVertex( a );
|
||||||
|
|
||||||
|
if( area( ap, a, an ) < 0 )
|
||||||
|
return area( a, b, an ) >= 0 && area( a, ap, b ) >= 0;
|
||||||
else
|
else
|
||||||
return area( a, b, a->prev ) < 0 || area( a, a->next, b ) < 0;
|
return area( a, b, ap ) < 0 || area( a, an, b ) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue