diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp index cd46ff3909..d3baf4499b 100644 --- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp +++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp @@ -677,9 +677,9 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta ROUNDRECT rr( SHAPE_RECT( aShape->GetPosition(), aShape->GetRectangleWidth(), aShape->GetRectangleHeight() ), - aShape->GetCornerRadius() ); + aShape->GetCornerRadius() ); SHAPE_POLY_SET poly; - rr.TransformToPolygon( poly ); + rr.TransformToPolygon( poly, aShape->GetMaxError() ); SHAPE_LINE_CHAIN& r_outline = poly.Outline( 0 ); r_outline.SetClosed( true ); diff --git a/common/eda_shape.cpp b/common/eda_shape.cpp index ed09019c40..153fdd6b10 100644 --- a/common/eda_shape.cpp +++ b/common/eda_shape.cpp @@ -607,7 +607,7 @@ void EDA_SHAPE::UpdateHatching() const { ROUNDRECT rr( SHAPE_RECT( getPosition(), GetRectangleWidth(), GetRectangleHeight() ), GetCornerRadius() ); - rr.TransformToPolygon( shapeBuffer ); + rr.TransformToPolygon( shapeBuffer, getMaxError() ); } break; @@ -824,7 +824,7 @@ void EDA_SHAPE::rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) // Convert non-cardinally-rotated rect to a diamond ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius ); m_shape = SHAPE_T::POLY; - rr.TransformToPolygon( m_poly ); + rr.TransformToPolygon( m_poly, getMaxError() ); m_poly.Rotate( aAngle, aRotCentre ); } @@ -1360,7 +1360,7 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const { ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius ); SHAPE_POLY_SET poly; - rr.TransformToPolygon( poly ); + rr.TransformToPolygon( poly, getMaxError() ); if( poly.CollideEdge( aPosition, nullptr, maxdist ) ) return true; @@ -1508,7 +1508,7 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co { ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius ); SHAPE_POLY_SET poly; - rr.TransformToPolygon( poly ); + rr.TransformToPolygon( poly, getMaxError() ); // Account for the width of the line arect.Inflate( GetWidth() / 2 ); @@ -1838,7 +1838,7 @@ std::vector EDA_SHAPE::makeEffectiveShapes( bool aEdgeOnly, bool aLineCh { ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius ); SHAPE_POLY_SET poly; - rr.TransformToPolygon( poly ); + rr.TransformToPolygon( poly, getMaxError() ); SHAPE_LINE_CHAIN outline = poly.Outline( 0 ); if( solidFill ) @@ -1846,6 +1846,8 @@ std::vector EDA_SHAPE::makeEffectiveShapes( bool aEdgeOnly, bool aLineCh if( width > 0 || !solidFill ) { + // TODO: need to handle arcs in outline! + for( int i = 0; i < outline.PointCount() - 1; ++i ) { effectiveShapes.emplace_back( new SHAPE_SEGMENT( outline.CPoint( i ), outline.CPoint( i + 1 ), diff --git a/eeschema/sch_item.cpp b/eeschema/sch_item.cpp index d635f2ca53..490cd5247b 100644 --- a/eeschema/sch_item.cpp +++ b/eeschema/sch_item.cpp @@ -613,6 +613,15 @@ int SCH_ITEM::compare( const SCH_ITEM& aOther, int aCompareFlags ) const } +int SCH_ITEM::GetMaxError() const +{ + if( SCHEMATIC* schematic = Schematic() ) + return schematic->Settings().m_MaxError; + else + return schIUScale.mmToIU( ARC_LOW_DEF_MM ); +} + + const wxString& SCH_ITEM::GetDefaultFont( const RENDER_SETTINGS* aSettings ) const { static wxString defaultName = KICAD_FONT_NAME; diff --git a/eeschema/sch_item.h b/eeschema/sch_item.h index 17e6efaff4..43f8395d32 100644 --- a/eeschema/sch_item.h +++ b/eeschema/sch_item.h @@ -326,6 +326,8 @@ public: */ std::vector ViewGetLayers() const override; + int GetMaxError() const; + /** * @return the size of the "pen" that be used to draw or plot this item */ diff --git a/eeschema/sch_painter.cpp b/eeschema/sch_painter.cpp index a66fbe3334..1de2c25e1f 100644 --- a/eeschema/sch_painter.cpp +++ b/eeschema/sch_painter.cpp @@ -2045,9 +2045,9 @@ void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer, bool aDimmed ) ROUNDRECT rr( SHAPE_RECT( shape->GetPosition(), shape->GetRectangleWidth(), shape->GetRectangleHeight() ), - shape->GetCornerRadius(), true /* normalize */ ); + shape->GetCornerRadius(), true /* normalize */ ); SHAPE_POLY_SET poly; - rr.TransformToPolygon( poly ); + rr.TransformToPolygon( poly, shape->GetMaxError() ); m_gal->DrawPolygon( poly ); } else @@ -2067,8 +2067,7 @@ void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer, bool aDimmed ) for( SHAPE* polySegment : polySegments ) pts.push_back( static_cast( polySegment )->GetSeg().A ); - pts.push_back( - static_cast( polySegments.back() )->GetSeg().B ); + pts.push_back( static_cast( polySegments.back() )->GetSeg().B ); for( SHAPE* polySegment : polySegments ) delete polySegment; diff --git a/eeschema/sch_shape.h b/eeschema/sch_shape.h index 3bd2587456..77e5ca35b3 100644 --- a/eeschema/sch_shape.h +++ b/eeschema/sch_shape.h @@ -145,13 +145,7 @@ protected: bool isMoving() const override { return IsMoving(); } - int getMaxError() const override - { - if( SCHEMATIC* schematic = Schematic() ) - return schematic->Settings().m_MaxError; - else - return schIUScale.mmToIU( ARC_LOW_DEF_MM ); - } + int getMaxError() const override { return GetMaxError(); } /** * @copydoc SCH_ITEM::compare() diff --git a/libs/kimath/include/geometry/roundrect.h b/libs/kimath/include/geometry/roundrect.h index 144a588c87..cb4b95655d 100644 --- a/libs/kimath/include/geometry/roundrect.h +++ b/libs/kimath/include/geometry/roundrect.h @@ -83,7 +83,7 @@ public: /** * Get the polygonal representation of the roundrect. */ - void TransformToPolygon( SHAPE_POLY_SET& aBuffer ) const; + void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aMaxError ) const; private: SHAPE_RECT m_rect; diff --git a/libs/kimath/src/geometry/roundrect.cpp b/libs/kimath/src/geometry/roundrect.cpp index d9409eb171..1ee847da91 100644 --- a/libs/kimath/src/geometry/roundrect.cpp +++ b/libs/kimath/src/geometry/roundrect.cpp @@ -78,8 +78,12 @@ ROUNDRECT ROUNDRECT::GetInflated( int aOutset ) const } -void ROUNDRECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer ) const +void ROUNDRECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aMaxError ) const { + // Roundrects won't have a gazillion points, so we use a higher definition than the + // typical maxError. + int maxError = aMaxError / 5; + const int idx = aBuffer.NewOutline(); SHAPE_LINE_CHAIN& outline = aBuffer.Outline( idx ); @@ -107,7 +111,7 @@ void ROUNDRECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer ) const { // It's a circle outline.Append( SHAPE_ARC( m_p0 + VECTOR2I( m_radius, m_radius ), - m_p0 + VECTOR2I( -m_radius, 0 ), ANGLE_360 ) ); + m_p0 + VECTOR2I( -m_radius, 0 ), ANGLE_360 ), maxError ); } else { @@ -125,13 +129,13 @@ void ROUNDRECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer ) const if( y_edge > 0 ) { - outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::NE ) ); + outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::NE ), maxError ); outline.Append( m_p0 + VECTOR2I( w, m_radius + y_edge ) ); - outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::SE ) ); + outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::SE ), maxError ); } else { - outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::E ) ); + outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::E ), maxError ); } // Bottom side @@ -139,22 +143,22 @@ void ROUNDRECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer ) const if( y_edge > 0 ) { - outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::SW ) ); + outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::SW ), maxError ); outline.Append( m_p0 + VECTOR2I( 0, m_radius ) ); - outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::NW ) ); + outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::NW ), maxError ); } else { - outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::W ) ); + outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::W ), maxError ); } } else { // x_edge is 0 but y_edge is not, so it's an oval the other way up outline.Append( m_p0 + VECTOR2I( 0, m_radius ) ); - outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::N ) ); + outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::N ), maxError ); outline.Append( m_p0 + VECTOR2I( w, m_radius + y_edge ) ); - outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::S ) ); + outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::S ), maxError ); } } diff --git a/libs/kimath/src/geometry/shape_rect.cpp b/libs/kimath/src/geometry/shape_rect.cpp index 930bf20dfa..69e78e95cb 100644 --- a/libs/kimath/src/geometry/shape_rect.cpp +++ b/libs/kimath/src/geometry/shape_rect.cpp @@ -123,13 +123,12 @@ const std::string SHAPE_RECT::Format( bool aCplusPlus ) const } -void SHAPE_RECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError, - ERROR_LOC aErrorLoc ) const +void SHAPE_RECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError, ERROR_LOC aErrorLoc ) const { if( m_radius > 0 ) { ROUNDRECT rr( *this, m_radius ); - rr.TransformToPolygon( aBuffer ); + rr.TransformToPolygon( aBuffer, aError ); return; } @@ -143,24 +142,16 @@ void SHAPE_RECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError, outline.SetClosed( true ); } + const SHAPE_LINE_CHAIN SHAPE_RECT::Outline() const { - if( m_radius > 0 ) - { - SHAPE_POLY_SET poly; - ROUNDRECT rr( *this, m_radius ); - rr.TransformToPolygon( poly ); - return poly.Outline( 0 ); - } + // TODO: we're DEPENDING on clients of this routine to use the actual arcs (if any) + // inserted into the SHAPE_LINE_CHAIN. They must NOT use the approximated segments + // because we don't know what IUScale to generate them in. - SHAPE_LINE_CHAIN rv; - rv.Append( m_p0 ); - rv.Append( m_p0.x, m_p0.y + m_h ); - rv.Append( m_p0.x + m_w, m_p0.y + m_h ); - rv.Append( m_p0.x + m_w, m_p0.y ); - rv.Append( m_p0 ); - rv.SetClosed( true ); - return rv; + SHAPE_POLY_SET buffer; + TransformToPolygon( buffer, SHAPE_ARC::DefaultAccuracyForPCB(), ERROR_INSIDE ); + return std::move( buffer.Outline( 0 ) ); } diff --git a/pcbnew/convert_shape_list_to_polygon.cpp b/pcbnew/convert_shape_list_to_polygon.cpp index 972bca0044..eff6fa30a7 100644 --- a/pcbnew/convert_shape_list_to_polygon.cpp +++ b/pcbnew/convert_shape_list_to_polygon.cpp @@ -225,9 +225,9 @@ static void processClosedShape( PCB_SHAPE* aShape, SHAPE_LINE_CHAIN& aContour, if( aShape->GetCornerRadius() > 0 ) { ROUNDRECT rr( SHAPE_RECT( aShape->GetStart(), aShape->GetRectangleWidth(), aShape->GetRectangleHeight() ), - aShape->GetCornerRadius() ); + aShape->GetCornerRadius(), true /* normalize */ ); SHAPE_POLY_SET poly; - rr.TransformToPolygon( poly ); + rr.TransformToPolygon( poly, aShape->GetMaxError() ); aContour.Append( poly.Outline( 0 ) ); for( int ii = 1; ii < aContour.PointCount(); ++ii ) diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index fdfa2db742..86c53b286f 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -1998,7 +1998,7 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer ) aShape->GetRectangleHeight() ), aShape->GetCornerRadius(), true /* normalize */ ); SHAPE_POLY_SET poly; - rr.TransformToPolygon( poly ); + rr.TransformToPolygon( poly, aShape->GetMaxError() ); SHAPE_LINE_CHAIN outline = poly.Outline( 0 ); if( aShape->IsProxyItem() ) diff --git a/pcbnew/tools/convert_tool.cpp b/pcbnew/tools/convert_tool.cpp index 1c0cf2d5a0..2c269ec8d0 100644 --- a/pcbnew/tools/convert_tool.cpp +++ b/pcbnew/tools/convert_tool.cpp @@ -1190,7 +1190,7 @@ int CONVERT_TOOL::CreateLines( const TOOL_EVENT& aEvent ) ROUNDRECT rrect( rect, graphic->GetCornerRadius(), true ); SHAPE_POLY_SET poly; - rrect.TransformToPolygon( poly ); + rrect.TransformToPolygon( poly, graphic->GetMaxError() ); processPolySet( poly, itemWidth ); break; } diff --git a/pcbnew/tools/item_modification_routine.cpp b/pcbnew/tools/item_modification_routine.cpp index 60005580ec..8c1cbed3a9 100644 --- a/pcbnew/tools/item_modification_routine.cpp +++ b/pcbnew/tools/item_modification_routine.cpp @@ -945,7 +945,7 @@ void OUTSET_ROUTINE::ProcessItem( BOARD_ITEM& aItem ) // No point doing a SHAPE_RECT as we may need to rotate it ROUNDRECT rrect( box, radius ); SHAPE_POLY_SET poly; - rrect.TransformToPolygon( poly ); + rrect.TransformToPolygon( poly, pad.GetMaxError() ); poly.Rotate( pad.GetOrientation(), pad.GetPosition() ); addPoly( poly ); @@ -986,29 +986,26 @@ void OUTSET_ROUTINE::ProcessItem( BOARD_ITEM& aItem ) box.Normalize(); SHAPE_RECT rect( box ); + int cornerRadius = pcb_shape.GetCornerRadius(); if( m_params.roundCorners ) - { - if( m_params.gridRounding.has_value() ) - rect = GetRectRoundedToGridOutwards( rect, *m_params.gridRounding ); + cornerRadius += m_params.outsetDistance; - try - { - int cornerRadius = pcb_shape.GetCornerRadius() + m_params.outsetDistance; - ROUNDRECT rrect( rect, cornerRadius ); - SHAPE_POLY_SET poly; - rrect.TransformToPolygon( poly ); - addPoly( poly ); - } - catch( ... ) - { - DisplayErrorMessage( nullptr, _( "Cannot create rectangle outset" ) ); - } + if( m_params.gridRounding.has_value() ) + rect = GetRectRoundedToGridOutwards( rect, *m_params.gridRounding ); + + if( cornerRadius > 0 ) + { + ROUNDRECT rrect( rect, cornerRadius ); + SHAPE_POLY_SET poly; + rrect.TransformToPolygon( poly, pcb_shape.GetMaxError() ); + addChain( poly.Outline( 0 ) ); } else { addRect( rect ); } + AddSuccess(); break; }