Maybe, just maybe, fix LibEdit arc parsing.

Fixes https://gitlab.com/kicad/code/kicad/issues/10455
This commit is contained in:
Jeff Young 2022-01-19 22:21:37 +00:00
parent af20d46d06
commit 3ba89f50ef
2 changed files with 37 additions and 77 deletions

View File

@ -494,10 +494,10 @@ void EDA_SHAPE::SetArcGeometry( const VECTOR2I& aStart, const VECTOR2I& aMid, co
m_arcCenter = CalcArcCenter( aStart, aMid, aEnd ); m_arcCenter = CalcArcCenter( aStart, aMid, aEnd );
m_endsSwapped = false; m_endsSwapped = false;
/** /*
* If the input winding doesn't match our internal winding, the calculated midpoint will end up * If the input winding doesn't match our internal winding, the calculated midpoint will end
* on the other side of the arc. In this case, we need to flip the start/end points and flag this * up on the other side of the arc. In this case, we need to flip the start/end points and
* change for the system * flag this change for the system.
*/ */
VECTOR2I new_mid = GetArcMid(); VECTOR2I new_mid = GetArcMid();
VECTOR2D dist( new_mid - aMid ); VECTOR2D dist( new_mid - aMid );

View File

@ -984,16 +984,29 @@ LIB_SHAPE* SCH_SEXPR_PARSER::parseArc()
if( hasMidPoint ) if( hasMidPoint )
{ {
arc->SetCenter( CalcArcCenter( arc->GetStart(), midPoint, arc->GetEnd() ) ); arc->SetCenter( CalcArcCenter( arc->GetStart(), midPoint, arc->GetEnd() ) );
/**
* Current file format stores start-mid-end and so doesn't care about winding. We
* store start-end with an implied winding internally though, so we need to swap the
* ends if they don't match what we're expecting.
*/
EDA_ANGLE start, end;
arc->CalcArcAngles( start, end );
if( start < end )
{
VECTOR2I temp = arc->GetStart();
arc->SetStart( arc->GetEnd() );
arc->SetEnd( temp );
}
} }
else if( hasAngles ) else if( hasAngles )
{ {
arc->SetCenter( center ); arc->SetCenter( center );
/** /*
* This accounts for an oddity in the old library format, where the symbol is overdefined. * Older versions stored start-end with an implied winding, but the winding was different
* The previous draw (based on wxwidgets) used start point and end point and always drew * between LibEdit and PCBNew. Since we now use a common class (EDA_SHAPE) for both we
* counter-clockwise. The new GAL draw takes center, radius and start/end angles. All of * need to flip one of them. LibEdit drew the short straw.
* these points were stored in the file, so we need to mimic the swapping of start/end
* points rather than using the stored angles in order to properly map edge cases.
*/ */
VECTOR2I temp = arc->GetStart(); VECTOR2I temp = arc->GetStart();
arc->SetStart( arc->GetEnd() ); arc->SetStart( arc->GetEnd() );
@ -2822,13 +2835,8 @@ SCH_SHAPE* SCH_SEXPR_PARSER::parseSchArc()
VECTOR2I startPoint; VECTOR2I startPoint;
VECTOR2I midPoint; VECTOR2I midPoint;
VECTOR2I endPoint; VECTOR2I endPoint;
VECTOR2I pos;
EDA_ANGLE startAngle;
EDA_ANGLE endAngle;
STROKE_PARAMS stroke( Mils2iu( DEFAULT_LINE_WIDTH_MILS ), PLOT_DASH_TYPE::DEFAULT ); STROKE_PARAMS stroke( Mils2iu( DEFAULT_LINE_WIDTH_MILS ), PLOT_DASH_TYPE::DEFAULT );
FILL_PARAMS fill; FILL_PARAMS fill;
bool hasMidPoint = false;
bool hasAngles = false;
std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC ); std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC );
for( token = NextTok(); token != T_RIGHT; token = NextTok() ) for( token = NextTok(); token != T_RIGHT; token = NextTok() )
@ -2848,7 +2856,6 @@ SCH_SHAPE* SCH_SEXPR_PARSER::parseSchArc()
case T_mid: case T_mid:
midPoint = parseXY(); midPoint = parseXY();
NeedRIGHT(); NeedRIGHT();
hasMidPoint = true;
break; break;
case T_end: case T_end:
@ -2856,44 +2863,6 @@ SCH_SHAPE* SCH_SEXPR_PARSER::parseSchArc()
NeedRIGHT(); NeedRIGHT();
break; break;
case T_radius:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_at:
pos = parseXY();
NeedRIGHT();
break;
case T_length:
parseInternalUnits( "radius length" );
NeedRIGHT();
break;
case T_angles:
{
startAngle = EDA_ANGLE( parseDouble( "start radius angle" ), DEGREES_T );
endAngle = EDA_ANGLE( parseDouble( "end radius angle" ), DEGREES_T );
startAngle.Normalize();
endAngle.Normalize();
NeedRIGHT();
hasAngles = true;
break;
}
default:
Expecting( "at, length, or angle" );
}
}
break;
case T_stroke: case T_stroke:
parseStroke( stroke ); parseStroke( stroke );
arc->SetStroke( stroke ); arc->SetStroke( stroke );
@ -2912,38 +2881,29 @@ SCH_SHAPE* SCH_SEXPR_PARSER::parseSchArc()
break; break;
default: default:
Expecting( "start, mid, end, radius, stroke, fill or uuid" ); Expecting( "start, mid, end, stroke, fill or uuid" );
} }
} }
arc->SetStart( startPoint ); arc->SetStart( startPoint );
arc->SetEnd( endPoint ); arc->SetEnd( endPoint );
arc->SetCenter( CalcArcCenter( arc->GetStart(), midPoint, arc->GetEnd() ) );
if( hasMidPoint ) /**
{ * Current file format stores start-mid-end and so doesn't care about winding. We store
VECTOR2I center = CalcArcCenter( arc->GetStart(), midPoint, arc->GetEnd() ); * start-end with an implied winding internally though, so we need to swap the ends if they
* don't match what we're expecting. (Note that what we're expecting is backwards from the
* LIB_SHAPE case because LibEdit has an upside-down coordinate system.)
*/
EDA_ANGLE start, end;
arc->CalcArcAngles( start, end );
arc->SetCenter( center ); if( start > end )
}
else if( hasAngles )
{ {
arc->SetCenter( pos ); VECTOR2I temp = arc->GetStart();
/** arc->SetStart( arc->GetEnd() );
* This accounts for an oddity in the old library format, where the symbol is overdefined. arc->SetEnd( temp );
* The previous draw (based on wxwidgets) used start point and end point and always drew
* counter-clockwise. The new GAL draw takes center, radius and start/end angles. All of
* these points were stored in the file, so we need to mimic the swapping of start/end
* points rather than using the stored angles in order to properly map edge cases.
*/
if( !TRANSFORM().MapAngles( &startAngle, &endAngle ) )
{
VECTOR2I temp = arc->GetStart();
arc->SetStart( arc->GetEnd() );
arc->SetEnd( temp );
}
} }
else
wxFAIL_MSG( "Setting arc without either midpoint or angles not implemented." );
return arc.release(); return arc.release();
} }