Fix a bunch more bugs in bezier approximation.

(cherry picked from commit e8e7282fe1eed4f2a633fea9c7bdb0e81be53f9b)
This commit is contained in:
Jeff Young 2025-05-26 17:30:37 +01:00
parent 29d0cdb546
commit d7a0555780
22 changed files with 110 additions and 114 deletions

View File

@ -303,7 +303,7 @@ bool EDA_SHAPE::Deserialize( const google::protobuf::Any &aContainer )
SetBezierC1( UnpackVector2( shape.bezier().control1() ) ); SetBezierC1( UnpackVector2( shape.bezier().control1() ) );
SetBezierC2( UnpackVector2( shape.bezier().control2() ) ); SetBezierC2( UnpackVector2( shape.bezier().control2() ) );
SetEnd( UnpackVector2( shape.bezier().end() ) ); SetEnd( UnpackVector2( shape.bezier().end() ) );
RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF ); RebuildBezierToSegmentsPointsList( getMaxError() );
} }
return true; return true;
@ -623,7 +623,7 @@ void EDA_SHAPE::scale( double aScale )
scalePt( m_end ); scalePt( m_end );
scalePt( m_bezierC1 ); scalePt( m_bezierC1 );
scalePt( m_bezierC2 ); scalePt( m_bezierC2 );
RebuildBezierToSegmentsPointsList( m_stroke.GetWidth() / 2 ); RebuildBezierToSegmentsPointsList( getMaxError() );
break; break;
default: default:
@ -727,7 +727,7 @@ void EDA_SHAPE::flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
MIRROR( m_bezierC1, aCentre, aFlipDirection ); MIRROR( m_bezierC1, aCentre, aFlipDirection );
MIRROR( m_bezierC2, aCentre, aFlipDirection ); MIRROR( m_bezierC2, aCentre, aFlipDirection );
RebuildBezierToSegmentsPointsList( m_stroke.GetWidth() / 2 ); RebuildBezierToSegmentsPointsList( getMaxError() );
break; break;
default: default:
@ -1742,7 +1742,7 @@ void EDA_SHAPE::beginEdit( const VECTOR2I& aPosition )
SetBezierC2( aPosition ); SetBezierC2( aPosition );
m_editState = 1; m_editState = 1;
RebuildBezierToSegmentsPointsList( GetWidth() / 2 ); RebuildBezierToSegmentsPointsList( getMaxError() );
break; break;
case SHAPE_T::POLY: case SHAPE_T::POLY:
@ -1824,7 +1824,7 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
case 3: SetBezierC2( aPosition ); break; case 3: SetBezierC2( aPosition ); break;
} }
RebuildBezierToSegmentsPointsList( GetWidth() / 2 ); RebuildBezierToSegmentsPointsList( getMaxError() );
} }
break; break;

View File

@ -228,7 +228,7 @@ void EDA_BEZIER_POINT_EDIT_BEHAVIOR::UpdateItem( const EDIT_POINT& aEditedPoint,
m_bezier.SetEnd( aPoints.Point( BEZIER_END ).GetPosition() ); m_bezier.SetEnd( aPoints.Point( BEZIER_END ).GetPosition() );
} }
m_bezier.RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF ); m_bezier.RebuildBezierToSegmentsPointsList( m_maxError );
} }

View File

@ -217,7 +217,7 @@ void GRAPHICS_IMPORTER_LIB_SYMBOL::AddSpline( const VECTOR2D& aStart,
spline->SetBezierC1( MapCoordinate( aBezierControl1 ) ); spline->SetBezierC1( MapCoordinate( aBezierControl1 ) );
spline->SetBezierC2( MapCoordinate( aBezierControl2 ) ); spline->SetBezierC2( MapCoordinate( aBezierControl2 ) );
spline->SetEnd( MapCoordinate( aEnd ) ); spline->SetEnd( MapCoordinate( aEnd ) );
spline->RebuildBezierToSegmentsPointsList( aStroke.GetWidth() / 2 ); spline->RebuildBezierToSegmentsPointsList( schIUScale.mmToIU( ARC_LOW_DEF_MM ) );
// If the spline is degenerated (i.e. a segment) add it as segment or discard it if // If the spline is degenerated (i.e. a segment) add it as segment or discard it if
// null (i.e. very small) length // null (i.e. very small) length

View File

@ -2276,7 +2276,7 @@ void SCH_IO_ALTIUM::ParseBezier( const std::map<wxString, wxString>& aProperties
} }
bezier->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) ); bezier->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
bezier->RebuildBezierToSegmentsPointsList( bezier->GetWidth() / 2 ); bezier->RebuildBezierToSegmentsPointsList( schIUScale.mmToIU( ARC_LOW_DEF_MM ) );
} }
} }
} }
@ -2680,7 +2680,7 @@ void SCH_IO_ALTIUM::ParseEllipticalArc( const std::map<wxString, wxString>& aPro
schbezier->SetBezierC2( bezier.C2 ); schbezier->SetBezierC2( bezier.C2 );
schbezier->SetEnd( bezier.End ); schbezier->SetEnd( bezier.End );
schbezier->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) ); schbezier->SetStroke( STROKE_PARAMS( elem.LineWidth, LINE_STYLE::SOLID ) );
schbezier->RebuildBezierToSegmentsPointsList( elem.LineWidth / 2 ); schbezier->RebuildBezierToSegmentsPointsList( schIUScale.mmToIU( ARC_LOW_DEF_MM ) );
currentScreen->Append( schbezier ); currentScreen->Append( schbezier );
} }
@ -2743,7 +2743,7 @@ void SCH_IO_ALTIUM::ParseEllipticalArc( const std::map<wxString, wxString>& aPro
} }
SetLibShapeLine( elem, schbezier, ALTIUM_SCH_RECORD::ELLIPTICAL_ARC ); SetLibShapeLine( elem, schbezier, ALTIUM_SCH_RECORD::ELLIPTICAL_ARC );
schbezier->RebuildBezierToSegmentsPointsList( elem.LineWidth / 2 ); schbezier->RebuildBezierToSegmentsPointsList( schIUScale.mmToIU( ARC_LOW_DEF_MM ) );
} }
} }
} }
@ -2877,7 +2877,7 @@ void SCH_IO_ALTIUM::ParseEllipse( const std::map<wxString, wxString>& aPropertie
schbezier->SetFillColor( fillColor ); schbezier->SetFillColor( fillColor );
schbezier->SetFillMode( fillMode ); schbezier->SetFillMode( fillMode );
schbezier->RebuildBezierToSegmentsPointsList( schbezier->GetWidth() / 2 ); schbezier->RebuildBezierToSegmentsPointsList( schIUScale.mmToIU( ARC_LOW_DEF_MM ) );
screen->Append( schbezier ); screen->Append( schbezier );
polyPoints.push_back( bezier.Start ); polyPoints.push_back( bezier.Start );
@ -2953,7 +2953,7 @@ void SCH_IO_ALTIUM::ParseEllipse( const std::map<wxString, wxString>& aPropertie
SetLibShapeLine( elem, libbezier, ALTIUM_SCH_RECORD::ELLIPSE ); SetLibShapeLine( elem, libbezier, ALTIUM_SCH_RECORD::ELLIPSE );
SetLibShapeFillAndColor( elem, libbezier, ALTIUM_SCH_RECORD::ELLIPSE, elem.Color ); SetLibShapeFillAndColor( elem, libbezier, ALTIUM_SCH_RECORD::ELLIPSE, elem.Color );
libbezier->RebuildBezierToSegmentsPointsList( libbezier->GetWidth() / 2 ); libbezier->RebuildBezierToSegmentsPointsList( schIUScale.mmToIU( ARC_LOW_DEF_MM ) );
polyPoints.push_back( libbezier->GetStart() ); polyPoints.push_back( libbezier->GetStart() );
} }

View File

@ -1403,7 +1403,7 @@ SCH_SHAPE* SCH_IO_KICAD_LEGACY_LIB_CACHE::loadBezier( LINE_READER& aReader )
pt.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) ); pt.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
bezier->SetEnd( pt ); bezier->SetEnd( pt );
bezier->RebuildBezierToSegmentsPointsList( bezier->GetWidth() / 2 ); bezier->RebuildBezierToSegmentsPointsList( schIUScale.mmToIU( ARC_LOW_DEF_MM ) );
if( *line != 0 ) if( *line != 0 )
bezier->SetFillMode( parseFillMode( aReader, line, &line ) ); bezier->SetFillMode( parseFillMode( aReader, line, &line ) );

View File

@ -85,7 +85,8 @@ SCH_IO_KICAD_SEXPR_PARSER::SCH_IO_KICAD_SEXPR_PARSER( LINE_READER* aLineReader,
m_lineReader( aLineReader ), m_lineReader( aLineReader ),
m_lastProgressLine( 0 ), m_lastProgressLine( 0 ),
m_lineCount( aLineCount ), m_lineCount( aLineCount ),
m_rootSheet( aRootSheet ) m_rootSheet( aRootSheet ),
m_maxError( ARC_LOW_DEF_MM * schIUScale.IU_PER_MM )
{ {
} }
@ -1432,7 +1433,7 @@ SCH_SHAPE* SCH_IO_KICAD_SEXPR_PARSER::parseSymbolBezier()
} }
} }
bezier->RebuildBezierToSegmentsPointsList( bezier->GetPenWidth() / 2 ); bezier->RebuildBezierToSegmentsPointsList( m_maxError );
return bezier.release(); return bezier.release();
} }
@ -2604,6 +2605,9 @@ void SCH_IO_KICAD_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet, bool aIsCopya
wxCHECK( screen != nullptr, /* void */ ); wxCHECK( screen != nullptr, /* void */ );
if( SCHEMATIC* schematic = dynamic_cast<SCHEMATIC*>( screen->GetParent() ) )
m_maxError = schematic->Settings().m_MaxError;
if( aIsCopyableOnly ) if( aIsCopyableOnly )
m_requiredVersion = aFileVersion; m_requiredVersion = aFileVersion;
@ -4246,7 +4250,7 @@ SCH_SHAPE* SCH_IO_KICAD_SEXPR_PARSER::parseSchBezier()
} }
} }
bezier->RebuildBezierToSegmentsPointsList( bezier->GetPenWidth() / 2 ); bezier->RebuildBezierToSegmentsPointsList( m_maxError );
return bezier.release(); return bezier.release();
} }

View File

@ -254,6 +254,9 @@ private:
/// The rootsheet for full project loads or null for importing a schematic. /// The rootsheet for full project loads or null for importing a schematic.
SCH_SHEET* m_rootSheet; SCH_SHEET* m_rootSheet;
/// Max deviation allowed when approximating bezier curves
int m_maxError;
}; };
#endif // SCH_IO_KICAD_SEXPR_PARSER_H_ #endif // SCH_IO_KICAD_SEXPR_PARSER_H_

View File

@ -27,6 +27,7 @@
#include <sch_item.h> #include <sch_item.h>
#include <eda_shape.h> #include <eda_shape.h>
#include <schematic.h>
class SCH_SHAPE : public SCH_ITEM, public EDA_SHAPE class SCH_SHAPE : public SCH_ITEM, public EDA_SHAPE
@ -139,7 +140,10 @@ protected:
int getMaxError() const override int getMaxError() const override
{ {
return schIUScale.mmToIU( ARC_HIGH_DEF_MM ); if( SCHEMATIC* schematic = Schematic() )
return schematic->Settings().m_MaxError;
else
return schIUScale.mmToIU( ARC_LOW_DEF_MM );
} }
/** /**

View File

@ -64,13 +64,13 @@ SCHEMATIC_SETTINGS::SCHEMATIC_SETTINGS( JSON_SETTINGS* aParent, const std::strin
m_SpiceSaveAllDissipations( false ), m_SpiceSaveAllDissipations( false ),
m_SpiceSaveAllEvents( true ), m_SpiceSaveAllEvents( true ),
m_SpiceModelCurSheetAsRoot( true ), m_SpiceModelCurSheetAsRoot( true ),
m_MaxError( ARC_LOW_DEF_MM * schIUScale.IU_PER_MM ),
m_NgspiceSettings( nullptr ) m_NgspiceSettings( nullptr )
{ {
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager(); SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
EESCHEMA_SETTINGS* cfg = mgr.GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ); EESCHEMA_SETTINGS* cfg = mgr.GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" );
int defaultLineThickness = int defaultLineThickness = cfg ? cfg->m_Drawing.default_line_thickness : DEFAULT_LINE_WIDTH_MILS;
cfg ? cfg->m_Drawing.default_line_thickness : DEFAULT_LINE_WIDTH_MILS;
int defaultTextSize = cfg ? cfg->m_Drawing.default_text_size : DEFAULT_TEXT_SIZE; int defaultTextSize = cfg ? cfg->m_Drawing.default_text_size : DEFAULT_TEXT_SIZE;
int defaultPinSymbolSize = cfg ? cfg->m_Drawing.pin_symbol_size : DEFAULT_TEXT_SIZE / 2; int defaultPinSymbolSize = cfg ? cfg->m_Drawing.pin_symbol_size : DEFAULT_TEXT_SIZE / 2;
int defaultJunctionSizeChoice = cfg ? cfg->m_Drawing.junction_size_choice : 3; int defaultJunctionSizeChoice = cfg ? cfg->m_Drawing.junction_size_choice : 3;

View File

@ -114,6 +114,9 @@ public:
KIFONT::METRICS m_FontMetrics; KIFONT::METRICS m_FontMetrics;
/// Max deviation allowable when approximating circles and curves (in IU).
int m_MaxError;
/** /**
* Ngspice simulator settings. * Ngspice simulator settings.
*/ */

View File

@ -918,8 +918,15 @@ void SCH_POINT_EDITOR::makePointsAndBehavior( EDA_ITEM* aItem )
m_editBehavior = std::make_unique<EDA_POLYGON_POINT_EDIT_BEHAVIOR>( *shape ); m_editBehavior = std::make_unique<EDA_POLYGON_POINT_EDIT_BEHAVIOR>( *shape );
break; break;
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
m_editBehavior = std::make_unique<EDA_BEZIER_POINT_EDIT_BEHAVIOR>( *shape ); {
int maxError = schIUScale.mmToIU( ARC_LOW_DEF_MM );
if( SCHEMATIC* schematic = shape->Schematic() )
maxError = schematic->Settings().m_MaxError;
m_editBehavior = std::make_unique<EDA_BEZIER_POINT_EDIT_BEHAVIOR>( *shape, maxError );
break; break;
}
default: default:
UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() ); UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
} }

View File

@ -79,7 +79,9 @@ struct EDA_IU_SCALE
constexpr EDA_IU_SCALE( double aIUPerMM ) : constexpr EDA_IU_SCALE( double aIUPerMM ) :
IU_PER_MM( aIUPerMM ), IU_PER_MILS( aIUPerMM * 0.0254 ), MM_PER_IU( 1 / IU_PER_MM ) IU_PER_MM( aIUPerMM ),
IU_PER_MILS( aIUPerMM * 0.0254 ),
MM_PER_IU( 1 / IU_PER_MM )
{ {
} }
@ -110,14 +112,19 @@ constexpr EDA_IU_SCALE drawSheetIUScale = EDA_IU_SCALE( PL_IU_PER_MM );
constexpr EDA_IU_SCALE schIUScale = EDA_IU_SCALE( SCH_IU_PER_MM ); constexpr EDA_IU_SCALE schIUScale = EDA_IU_SCALE( SCH_IU_PER_MM );
constexpr EDA_IU_SCALE unityScale = EDA_IU_SCALE( 1 ); constexpr EDA_IU_SCALE unityScale = EDA_IU_SCALE( 1 );
// Allowed error to approximate an arg by segments, in millimeters
constexpr double ARC_LOW_DEF_MM = 0.02;
constexpr double ARC_HIGH_DEF_MM = 0.005;
#ifndef SWIG #ifndef SWIG
// The max error is the distance between the middle of a segment, and the circle // The max error is the distance between the middle of a segment, and the circle
// for circle/arc to segment approximation. // for circle/arc to segment approximation.
// Warning: too small values can create very long calculation time in zone filling // Warning: too small values can create very long calculation time in zone filling
// 0.05 to 0.005 mm are reasonable values // 0.05 to 0.005 mm are reasonable values
constexpr int ARC_LOW_DEF = pcbIUScale.mmToIU( 0.02 ); // Allowed error to approximate an arg by segments, in Pcbnew IU
constexpr int ARC_HIGH_DEF = pcbIUScale.mmToIU( 0.005 ); constexpr int ARC_LOW_DEF = pcbIUScale.mmToIU( ARC_LOW_DEF_MM );
constexpr int ARC_HIGH_DEF = pcbIUScale.mmToIU( ARC_HIGH_DEF_MM );
#endif #endif
#endif // _BASE_UNITS_H_ #endif // _BASE_UNITS_H_

View File

@ -128,7 +128,9 @@ protected:
class POLYGON_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR class POLYGON_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
{ {
public: public:
POLYGON_POINT_EDIT_BEHAVIOR( SHAPE_POLY_SET& aPolygon ) : m_polygon( aPolygon ) {} POLYGON_POINT_EDIT_BEHAVIOR( SHAPE_POLY_SET& aPolygon ) :
m_polygon( aPolygon )
{}
/** /**
* Build the edit points for the given polygon outline. * Build the edit points for the given polygon outline.
@ -193,7 +195,8 @@ public:
class EDA_SEGMENT_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR class EDA_SEGMENT_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
{ {
public: public:
EDA_SEGMENT_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aSegment ) : m_segment( aSegment ) EDA_SEGMENT_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aSegment ) :
m_segment( aSegment )
{ {
wxASSERT( aSegment.GetShape() == SHAPE_T::SEGMENT ); wxASSERT( aSegment.GetShape() == SHAPE_T::SEGMENT );
} }
@ -228,7 +231,8 @@ private:
class EDA_CIRCLE_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR class EDA_CIRCLE_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
{ {
public: public:
EDA_CIRCLE_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aCircle ) : m_circle( aCircle ) EDA_CIRCLE_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aCircle ) :
m_circle( aCircle )
{ {
wxASSERT( aCircle.GetShape() == SHAPE_T::CIRCLE ); wxASSERT( aCircle.GetShape() == SHAPE_T::CIRCLE );
} }
@ -263,7 +267,9 @@ private:
class EDA_BEZIER_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR class EDA_BEZIER_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
{ {
public: public:
EDA_BEZIER_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aBezier ) : m_bezier( aBezier ) EDA_BEZIER_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aBezier, int aMaxError ) :
m_bezier( aBezier ),
m_maxError( aMaxError )
{ {
wxASSERT( aBezier.GetShape() == SHAPE_T::BEZIER ); wxASSERT( aBezier.GetShape() == SHAPE_T::BEZIER );
} }
@ -288,6 +294,7 @@ protected:
private: private:
EDA_SHAPE& m_bezier; EDA_SHAPE& m_bezier;
int m_maxError;
}; };

View File

@ -398,7 +398,7 @@ bool doConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aShapeList, SHAPE_POLY_
} }
// Ensure the approximated Bezier shape is built // Ensure the approximated Bezier shape is built
graphic->RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF ); graphic->RebuildBezierToSegmentsPointsList( aErrorMax );
if( reverse ) if( reverse )
{ {

View File

@ -37,7 +37,7 @@
#include <pcb_shape.h> #include <pcb_shape.h>
#include <macros.h> #include <macros.h>
#include <widgets/unit_binder.h> #include <widgets/unit_binder.h>
#include <board_design_settings.h>
#include <dialog_shape_properties_base.h> #include <dialog_shape_properties_base.h>
#include <tools/drawing_tool.h> #include <tools/drawing_tool.h>
@ -1166,7 +1166,7 @@ bool DIALOG_SHAPE_PROPERTIES::TransferDataFromWindow()
else else
m_item->SetLocalSolderMaskMargin( m_solderMaskMargin.GetIntValue() ); m_item->SetLocalSolderMaskMargin( m_solderMaskMargin.GetIntValue() );
m_item->RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF ); m_item->RebuildBezierToSegmentsPointsList( m_parent->GetDesignSettings().m_MaxError );
if( m_item->IsOnCopperLayer() ) if( m_item->IsOnCopperLayer() )
m_item->SetNetCode( m_netSelector->GetSelectedNetcode() ); m_item->SetNetCode( m_netSelector->GetSelectedNetcode() );

View File

@ -312,7 +312,7 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run()
{ {
SHAPE_LINE_CHAIN asPoly; SHAPE_LINE_CHAIN asPoly;
shape->RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF ); shape->RebuildBezierToSegmentsPointsList( errorMax );
for( const VECTOR2I& pt : shape->GetBezierPoints() ) for( const VECTOR2I& pt : shape->GetBezierPoints() )
asPoly.Append( pt ); asPoly.Append( pt );

View File

@ -43,7 +43,8 @@ GRAPHICS_CLEANER::GRAPHICS_CLEANER( const DRAWINGS& aDrawings, FOOTPRINT* aParen
m_commit( aCommit ), m_commit( aCommit ),
m_toolMgr( aToolMgr ), m_toolMgr( aToolMgr ),
m_dryRun( true ), m_dryRun( true ),
m_epsilon( 0 ), m_epsilon( 1 ),
m_maxError( ARC_HIGH_DEF ),
m_outlinesTolerance( 0 ), m_outlinesTolerance( 0 ),
m_itemsList( nullptr ) m_itemsList( nullptr )
{ {
@ -59,7 +60,8 @@ void GRAPHICS_CLEANER::CleanupBoard( bool
m_itemsList = aItemsList; m_itemsList = aItemsList;
m_outlinesTolerance = aTolerance; m_outlinesTolerance = aTolerance;
m_epsilon = m_commit.GetBoard()->GetDesignSettings().m_MaxError; m_epsilon = m_commit.GetBoard()->GetDesignSettings().GetDRCEpsilon();
m_maxError = m_commit.GetBoard()->GetDesignSettings().m_MaxError;
// Clear the flag used to mark some shapes as deleted, in dry run: // Clear the flag used to mark some shapes as deleted, in dry run:
for( BOARD_ITEM* drawing : m_drawings ) for( BOARD_ITEM* drawing : m_drawings )
@ -105,7 +107,7 @@ bool GRAPHICS_CLEANER::isNullShape( PCB_SHAPE* aShape )
return aShape->GetPointCount() == 0; return aShape->GetPointCount() == 0;
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
aShape->RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF ); aShape->RebuildBezierToSegmentsPointsList( m_maxError );
// If the Bezier points list contains 2 points, it is equivalent to a segment // If the Bezier points list contains 2 points, it is equivalent to a segment
if( aShape->GetBezierPoints().size() == 2 ) if( aShape->GetBezierPoints().size() == 2 )

View File

@ -61,12 +61,13 @@ private:
private: private:
const DRAWINGS& m_drawings; const DRAWINGS& m_drawings;
FOOTPRINT* m_parentFootprint; // nullptr if not in Footprint Editor FOOTPRINT* m_parentFootprint; // nullptr if not in Footprint Editor
BOARD_COMMIT& m_commit; BOARD_COMMIT& m_commit;
TOOL_MANAGER* m_toolMgr; TOOL_MANAGER* m_toolMgr;
bool m_dryRun; bool m_dryRun;
int m_epsilon; int m_epsilon;
int m_outlinesTolerance; int m_maxError;
int m_outlinesTolerance;
std::vector<std::shared_ptr<CLEANUP_ITEM>>* m_itemsList; std::vector<std::shared_ptr<CLEANUP_ITEM>>* m_itemsList;
}; };

View File

@ -2937,7 +2937,7 @@ PCB_SHAPE* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_SHAPE( BOARD_ITEM* aParent )
shape->SetBezierC1( parseXY()); shape->SetBezierC1( parseXY());
shape->SetBezierC2( parseXY()); shape->SetBezierC2( parseXY());
shape->SetEnd( parseXY() ); shape->SetEnd( parseXY() );
shape->RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF ); shape->RebuildBezierToSegmentsPointsList( m_board->GetDesignSettings().m_MaxError );
NeedRIGHT(); NeedRIGHT();
break; break;

View File

@ -500,37 +500,7 @@ void PCB_SHAPE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
void PCB_SHAPE::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) void PCB_SHAPE::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
{ {
// Mirror an edge of the footprint. the layer is not modified flip( aCentre, aFlipDirection );
// This is a footprint shape modification.
switch( GetShape() )
{
case SHAPE_T::ARC:
case SHAPE_T::SEGMENT:
case SHAPE_T::RECTANGLE:
case SHAPE_T::CIRCLE:
case SHAPE_T::BEZIER:
MIRROR( m_start, aCentre, aFlipDirection );
MIRROR( m_end, aCentre, aFlipDirection );
MIRROR( m_arcCenter, aCentre, aFlipDirection );
MIRROR( m_bezierC1, aCentre, aFlipDirection );
MIRROR( m_bezierC2, aCentre, aFlipDirection );
if( GetShape() == SHAPE_T::ARC )
std::swap( m_start, m_end );
if( GetShape() == SHAPE_T::BEZIER )
RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF );
break;
case SHAPE_T::POLY:
m_poly.Mirror( aCentre, aFlipDirection );
break;
default:
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
}
} }

View File

@ -2827,29 +2827,13 @@ bool DRAWING_TOOL::drawArc( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
} }
/**
* Update a bezier PCB_SHAPE from the current state of a Bezier Geometry Manager.
*/
static void updateBezierFromConstructionMgr( const KIGFX::PREVIEW::BEZIER_GEOM_MANAGER& aMgr,
PCB_SHAPE& aBezier )
{
VECTOR2I vec = aMgr.GetStart();
aBezier.SetStart( vec );
aBezier.SetBezierC1( aMgr.GetControlC1() );
aBezier.SetEnd( aMgr.GetEnd() );
aBezier.SetBezierC2( aMgr.GetControlC2() );
// Need this for the length preview to work
aBezier.RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF );
}
std::unique_ptr<PCB_SHAPE> DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aTool, std::unique_ptr<PCB_SHAPE> DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aTool,
const OPT_VECTOR2I& aStartingPoint, const OPT_VECTOR2I& aStartingPoint,
const OPT_VECTOR2I& aStartingControl1Point, const OPT_VECTOR2I& aStartingControl1Point,
DRAW_ONE_RESULT& aResult ) DRAW_ONE_RESULT& aResult )
{ {
int maxError = board()->GetDesignSettings().m_MaxError;
std::unique_ptr<PCB_SHAPE> bezier = std::make_unique<PCB_SHAPE>( m_frame->GetModel() ); std::unique_ptr<PCB_SHAPE> bezier = std::make_unique<PCB_SHAPE>( m_frame->GetModel() );
bezier->SetShape( SHAPE_T::BEZIER ); bezier->SetShape( SHAPE_T::BEZIER );
bezier->SetFlags( IS_NEW ); bezier->SetFlags( IS_NEW );
@ -2875,26 +2859,29 @@ std::unique_ptr<PCB_SHAPE> DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo
m_view->Add( &bezierAsst ); m_view->Add( &bezierAsst );
PCB_GRID_HELPER grid( m_toolMgr, m_frame->GetMagneticItemsSettings() ); PCB_GRID_HELPER grid( m_toolMgr, m_frame->GetMagneticItemsSettings() );
const auto setCursor = [&]() const auto setCursor =
{ [&]()
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL ); {
}; m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
};
const auto resetProgress = [&]() const auto resetProgress =
{ [&]()
preview.Clear(); {
bezier.reset(); preview.Clear();
}; bezier.reset();
};
m_controls->ShowCursor( true ); m_controls->ShowCursor( true );
m_controls->ForceCursorPosition( false ); m_controls->ForceCursorPosition( false );
// Set initial cursor // Set initial cursor
setCursor(); setCursor();
const auto started = [&]() const auto started =
{ [&]()
return bezierManager.GetStep() > KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_START; {
}; return bezierManager.GetStep() > KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_START;
};
aResult = DRAW_ONE_RESULT::ACCEPTED; aResult = DRAW_ONE_RESULT::ACCEPTED;
bool priming = false; bool priming = false;
@ -3010,15 +2997,11 @@ std::unique_ptr<PCB_SHAPE> DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo
{ {
// Use the current point for all remaining points // Use the current point for all remaining points
while( bezierManager.GetStep() < KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_END ) while( bezierManager.GetStep() < KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_END )
{
bezierManager.AddPoint( cursorPos, true ); bezierManager.AddPoint( cursorPos, true );
}
} }
if( bezierManager.GetStep() == KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_END ) if( bezierManager.GetStep() == KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_END )
{
preview.Add( bezier.get() ); preview.Add( bezier.get() );
}
// Return to the caller for a reset // Return to the caller for a reset
if( doubleClick ) if( doubleClick )
@ -3033,9 +3016,7 @@ std::unique_ptr<PCB_SHAPE> DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo
bezierManager.RemoveLastPoint(); bezierManager.RemoveLastPoint();
if( bezierManager.GetStep() < KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_END ) if( bezierManager.GetStep() < KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_END )
{
preview.Remove( bezier.get() ); preview.Remove( bezier.get() );
}
} }
else if( evt->IsMotion() ) else if( evt->IsMotion() )
{ {
@ -3126,9 +3107,8 @@ std::unique_ptr<PCB_SHAPE> DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo
m_view->Update( &bezierAsst ); m_view->Update( &bezierAsst );
evt->SetPassEvent(); evt->SetPassEvent();
} }
else if( started() else if( started() && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
&& ( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) || evt->IsAction( &ACTIONS::redo ) ) )
|| evt->IsAction( &ACTIONS::redo ) ) )
{ {
wxBell(); wxBell();
} }
@ -3143,7 +3123,12 @@ std::unique_ptr<PCB_SHAPE> DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aToo
} }
else if( bezierManager.HasGeometryChanged() ) else if( bezierManager.HasGeometryChanged() )
{ {
updateBezierFromConstructionMgr( bezierManager, *bezier ); bezier->SetStart( bezierManager.GetStart() );
bezier->SetBezierC1( bezierManager.GetControlC1() );
bezier->SetEnd( bezierManager.GetEnd() );
bezier->SetBezierC2( bezierManager.GetControlC2() );
bezier->RebuildBezierToSegmentsPointsList( maxError );
m_view->Update( &preview ); m_view->Update( &preview );
m_view->Update( &bezierAsst ); m_view->Update( &bezierAsst );

View File

@ -2008,9 +2008,11 @@ std::shared_ptr<EDIT_POINTS> PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem )
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
m_editorBehavior = std::make_unique<EDA_SEGMENT_POINT_EDIT_BEHAVIOR>( *shape ); m_editorBehavior = std::make_unique<EDA_SEGMENT_POINT_EDIT_BEHAVIOR>( *shape );
break; break;
case SHAPE_T::RECTANGLE: case SHAPE_T::RECTANGLE:
m_editorBehavior = std::make_unique<RECTANGLE_POINT_EDIT_BEHAVIOR>( *shape ); m_editorBehavior = std::make_unique<RECTANGLE_POINT_EDIT_BEHAVIOR>( *shape );
break; break;
case SHAPE_T::ARC: case SHAPE_T::ARC:
m_editorBehavior = std::make_unique<ARC_POINT_EDIT_BEHAVIOR>( *shape, m_arcEditMode, m_editorBehavior = std::make_unique<ARC_POINT_EDIT_BEHAVIOR>( *shape, m_arcEditMode,
*getViewControls() ); *getViewControls() );
@ -2025,7 +2027,8 @@ std::shared_ptr<EDIT_POINTS> PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem )
break; break;
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
m_editorBehavior = std::make_unique<EDA_BEZIER_POINT_EDIT_BEHAVIOR>( *shape ); m_editorBehavior = std::make_unique<EDA_BEZIER_POINT_EDIT_BEHAVIOR>(
*shape, board()->GetDesignSettings().m_MaxError );
break; break;
default: // suppress warnings default: // suppress warnings