Handle closed shapes being processed after other shapes.
Fixes https://gitlab.com/kicad/code/kicad/issues/6845
This commit is contained in:
parent
fd77982496
commit
ab97035ecb
|
@ -197,10 +197,10 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool polygonComplete = false;
|
bool polygonComplete = false;
|
||||||
|
bool selfIntersecting = false;
|
||||||
|
|
||||||
wxString msg;
|
wxString msg;
|
||||||
PCB_SHAPE* graphic;
|
PCB_SHAPE* graphic = nullptr;
|
||||||
wxPoint prevPt;
|
|
||||||
|
|
||||||
std::set<PCB_SHAPE*> startCandidates( aSegList.begin(), aSegList.end() );
|
std::set<PCB_SHAPE*> startCandidates( aSegList.begin(), aSegList.end() );
|
||||||
|
|
||||||
|
@ -337,8 +337,10 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
|
||||||
// Grab the left most point, assume its on the board's perimeter, and see if we can put
|
// Grab the left most point, assume its on the board's perimeter, and see if we can put
|
||||||
// enough graphics together by matching endpoints to formulate a cohesive polygon.
|
// enough graphics together by matching endpoints to formulate a cohesive polygon.
|
||||||
|
|
||||||
graphic = (PCB_SHAPE*) aSegList[xmini];
|
PCB_SHAPE* prevGraphic = nullptr;
|
||||||
|
wxPoint prevPt;
|
||||||
|
|
||||||
|
graphic = (PCB_SHAPE*) aSegList[xmini];
|
||||||
graphic->SetFlags( SKIP_STRUCT );
|
graphic->SetFlags( SKIP_STRUCT );
|
||||||
startCandidates.erase( graphic );
|
startCandidates.erase( graphic );
|
||||||
|
|
||||||
|
@ -413,116 +415,135 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
|
||||||
{
|
{
|
||||||
switch( graphic->GetShape() )
|
switch( graphic->GetShape() )
|
||||||
{
|
{
|
||||||
case S_SEGMENT:
|
case S_RECT:
|
||||||
|
case S_CIRCLE:
|
||||||
|
{
|
||||||
|
// As a non-first item, closed shapes can't be anything but self-intersecting
|
||||||
|
|
||||||
|
if( aErrorHandler )
|
||||||
{
|
{
|
||||||
wxPoint nextPt;
|
wxASSERT( prevGraphic );
|
||||||
|
(*aErrorHandler)( _( "(self-intersecting)" ), prevGraphic, graphic, prevPt );
|
||||||
// Use the line segment end point furthest away from prevPt as we assume
|
|
||||||
// the other end to be ON prevPt or very close to it.
|
|
||||||
|
|
||||||
if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
|
|
||||||
nextPt = graphic->GetEnd();
|
|
||||||
else
|
|
||||||
nextPt = graphic->GetStart();
|
|
||||||
|
|
||||||
aPolygons.Append( nextPt );
|
|
||||||
segOwners[ std::make_pair( prevPt, nextPt ) ] = graphic;
|
|
||||||
prevPt = nextPt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selfIntersecting = true;
|
||||||
|
|
||||||
|
// A closed shape will finish where it started, so no point in updating prevPt
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_SEGMENT:
|
||||||
|
{
|
||||||
|
wxPoint nextPt;
|
||||||
|
|
||||||
|
// Use the line segment end point furthest away from prevPt as we assume
|
||||||
|
// the other end to be ON prevPt or very close to it.
|
||||||
|
|
||||||
|
if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
|
||||||
|
nextPt = graphic->GetEnd();
|
||||||
|
else
|
||||||
|
nextPt = graphic->GetStart();
|
||||||
|
|
||||||
|
aPolygons.Append( nextPt );
|
||||||
|
segOwners[ std::make_pair( prevPt, nextPt ) ] = graphic;
|
||||||
|
prevPt = nextPt;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_ARC:
|
case S_ARC:
|
||||||
|
{
|
||||||
// We do not support arcs in polygons, so approximate an arc with a series of
|
// We do not support arcs in polygons, so approximate an arc with a series of
|
||||||
// short lines and put those line segments into the !same! PATH.
|
// short lines and put those line segments into the !same! PATH.
|
||||||
|
|
||||||
|
wxPoint pstart = graphic->GetArcStart();
|
||||||
|
wxPoint pend = graphic->GetArcEnd();
|
||||||
|
wxPoint pcenter = graphic->GetCenter();
|
||||||
|
double angle = -graphic->GetAngle();
|
||||||
|
double radius = graphic->GetRadius();
|
||||||
|
int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 );
|
||||||
|
|
||||||
|
if( !close_enough( prevPt, pstart, aChainingEpsilon ) )
|
||||||
{
|
{
|
||||||
wxPoint pstart = graphic->GetArcStart();
|
wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aChainingEpsilon ) );
|
||||||
wxPoint pend = graphic->GetArcEnd();
|
|
||||||
wxPoint pcenter = graphic->GetCenter();
|
|
||||||
double angle = -graphic->GetAngle();
|
|
||||||
double radius = graphic->GetRadius();
|
|
||||||
int steps = GetArcToSegmentCount( radius, aErrorMax, angle / 10.0 );
|
|
||||||
|
|
||||||
if( !close_enough( prevPt, pstart, aChainingEpsilon ) )
|
angle = -angle;
|
||||||
{
|
std::swap( pstart, pend );
|
||||||
wxASSERT( close_enough( prevPt, graphic->GetArcEnd(), aChainingEpsilon ) );
|
|
||||||
|
|
||||||
angle = -angle;
|
|
||||||
std::swap( pstart, pend );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create intermediate points between start and end:
|
|
||||||
for( int step = 1; step < steps; ++step )
|
|
||||||
{
|
|
||||||
double rotation = ( angle * step ) / steps;
|
|
||||||
wxPoint pt = pstart;
|
|
||||||
RotatePoint( &pt, pcenter, rotation );
|
|
||||||
|
|
||||||
aPolygons.Append( pt );
|
|
||||||
segOwners[ std::make_pair( prevPt, pt ) ] = graphic;
|
|
||||||
prevPt = pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the last arc end point
|
|
||||||
aPolygons.Append( pend );
|
|
||||||
segOwners[ std::make_pair( prevPt, pend ) ] = graphic;
|
|
||||||
prevPt = pend;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create intermediate points between start and end:
|
||||||
|
for( int step = 1; step < steps; ++step )
|
||||||
|
{
|
||||||
|
double rotation = ( angle * step ) / steps;
|
||||||
|
wxPoint pt = pstart;
|
||||||
|
RotatePoint( &pt, pcenter, rotation );
|
||||||
|
|
||||||
|
aPolygons.Append( pt );
|
||||||
|
segOwners[ std::make_pair( prevPt, pt ) ] = graphic;
|
||||||
|
prevPt = pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the last arc end point
|
||||||
|
aPolygons.Append( pend );
|
||||||
|
segOwners[ std::make_pair( prevPt, pend ) ] = graphic;
|
||||||
|
prevPt = pend;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_CURVE:
|
case S_CURVE:
|
||||||
|
{
|
||||||
// We do not support Bezier curves in polygons, so approximate with a series
|
// We do not support Bezier curves in polygons, so approximate with a series
|
||||||
// of short lines and put those line segments into the !same! PATH.
|
// of short lines and put those line segments into the !same! PATH.
|
||||||
|
|
||||||
|
wxPoint nextPt;
|
||||||
|
bool first = true;
|
||||||
|
bool reverse = false;
|
||||||
|
|
||||||
|
// Use the end point furthest away from
|
||||||
|
// prevPt as we assume the other end to be ON prevPt or
|
||||||
|
// very close to it.
|
||||||
|
|
||||||
|
if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
|
||||||
{
|
{
|
||||||
wxPoint nextPt;
|
nextPt = graphic->GetEnd();
|
||||||
bool first = true;
|
|
||||||
bool reverse = false;
|
|
||||||
|
|
||||||
// Use the end point furthest away from
|
|
||||||
// prevPt as we assume the other end to be ON prevPt or
|
|
||||||
// very close to it.
|
|
||||||
|
|
||||||
if( close_st( prevPt, graphic->GetStart(), graphic->GetEnd() ) )
|
|
||||||
{
|
|
||||||
nextPt = graphic->GetEnd();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nextPt = graphic->GetStart();
|
|
||||||
reverse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( reverse )
|
|
||||||
{
|
|
||||||
for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- )
|
|
||||||
{
|
|
||||||
const wxPoint& pt = graphic->GetBezierPoints()[jj];
|
|
||||||
aPolygons.Append( pt );
|
|
||||||
|
|
||||||
if( first )
|
|
||||||
first = false;
|
|
||||||
else
|
|
||||||
segOwners[ std::make_pair( prevPt, pt ) ] = graphic;
|
|
||||||
|
|
||||||
prevPt = pt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( const wxPoint& pt : graphic->GetBezierPoints() )
|
|
||||||
{
|
|
||||||
aPolygons.Append( pt );
|
|
||||||
|
|
||||||
if( first )
|
|
||||||
first = false;
|
|
||||||
else
|
|
||||||
segOwners[ std::make_pair( prevPt, pt ) ] = graphic;
|
|
||||||
|
|
||||||
prevPt = pt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prevPt = nextPt;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextPt = graphic->GetStart();
|
||||||
|
reverse = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( reverse )
|
||||||
|
{
|
||||||
|
for( int jj = graphic->GetBezierPoints().size()-1; jj >= 0; jj-- )
|
||||||
|
{
|
||||||
|
const wxPoint& pt = graphic->GetBezierPoints()[jj];
|
||||||
|
aPolygons.Append( pt );
|
||||||
|
|
||||||
|
if( first )
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
segOwners[ std::make_pair( prevPt, pt ) ] = graphic;
|
||||||
|
|
||||||
|
prevPt = pt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( const wxPoint& pt : graphic->GetBezierPoints() )
|
||||||
|
{
|
||||||
|
aPolygons.Append( pt );
|
||||||
|
|
||||||
|
if( first )
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
segOwners[ std::make_pair( prevPt, pt ) ] = graphic;
|
||||||
|
|
||||||
|
prevPt = pt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prevPt = nextPt;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -537,6 +558,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
|
||||||
|
|
||||||
if( nextGraphic && !( nextGraphic->GetFlags() & SKIP_STRUCT ) )
|
if( nextGraphic && !( nextGraphic->GetFlags() & SKIP_STRUCT ) )
|
||||||
{
|
{
|
||||||
|
prevGraphic = graphic;
|
||||||
graphic = nextGraphic;
|
graphic = nextGraphic;
|
||||||
graphic->SetFlags( SKIP_STRUCT );
|
graphic->SetFlags( SKIP_STRUCT );
|
||||||
startCandidates.erase( graphic );
|
startCandidates.erase( graphic );
|
||||||
|
@ -815,7 +837,6 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
|
||||||
// All of the silliness that follows is to work around the segment iterator while checking
|
// All of the silliness that follows is to work around the segment iterator while checking
|
||||||
// for collisions.
|
// for collisions.
|
||||||
// TODO: Implement proper segment and point iterators that follow std
|
// TODO: Implement proper segment and point iterators that follow std
|
||||||
bool selfIntersecting = false;
|
|
||||||
|
|
||||||
for( auto seg1 = aPolygons.IterateSegmentsWithHoles(); seg1; seg1++ )
|
for( auto seg1 = aPolygons.IterateSegmentsWithHoles(); seg1; seg1++ )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue