mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-13 17:53:11 +02:00
ADDED: Rounded Rectangles
Fixes https://gitlab.com/kicad/code/kicad/-/issues/4742
This commit is contained in:
parent
e282dca102
commit
8acf5c1a25
@ -371,6 +371,7 @@ message GraphicRectangleAttributes
|
|||||||
{
|
{
|
||||||
kiapi.common.types.Vector2 top_left = 1;
|
kiapi.common.types.Vector2 top_left = 1;
|
||||||
kiapi.common.types.Vector2 bottom_right = 2;
|
kiapi.common.types.Vector2 bottom_right = 2;
|
||||||
|
kiapi.common.types.Distance corner_radius = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GraphicArcAttributes
|
message GraphicArcAttributes
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <geometry/shape_simple.h>
|
#include <geometry/shape_simple.h>
|
||||||
#include <geometry/shape_segment.h>
|
#include <geometry/shape_segment.h>
|
||||||
#include <geometry/shape_rect.h>
|
#include <geometry/shape_rect.h>
|
||||||
|
#include <geometry/roundrect.h>
|
||||||
#include <geometry/geometry_utils.h>
|
#include <geometry/geometry_utils.h>
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
@ -54,6 +55,7 @@ EDA_SHAPE::EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill ) :
|
|||||||
m_hatchingDirty( true ),
|
m_hatchingDirty( true ),
|
||||||
m_rectangleHeight( 0 ),
|
m_rectangleHeight( 0 ),
|
||||||
m_rectangleWidth( 0 ),
|
m_rectangleWidth( 0 ),
|
||||||
|
m_cornerRadius( 0 ),
|
||||||
m_segmentLength( 0 ),
|
m_segmentLength( 0 ),
|
||||||
m_editState( 0 ),
|
m_editState( 0 ),
|
||||||
m_proxyItem( false )
|
m_proxyItem( false )
|
||||||
@ -73,6 +75,7 @@ EDA_SHAPE::EDA_SHAPE( const SHAPE& aShape ) :
|
|||||||
m_hatchingDirty( true ),
|
m_hatchingDirty( true ),
|
||||||
m_rectangleHeight( 0 ),
|
m_rectangleHeight( 0 ),
|
||||||
m_rectangleWidth( 0 ),
|
m_rectangleWidth( 0 ),
|
||||||
|
m_cornerRadius( 0 ),
|
||||||
m_segmentLength( 0 ),
|
m_segmentLength( 0 ),
|
||||||
m_editState( 0 ),
|
m_editState( 0 ),
|
||||||
m_proxyItem( false )
|
m_proxyItem( false )
|
||||||
@ -188,6 +191,7 @@ void EDA_SHAPE::Serialize( google::protobuf::Any &aContainer ) const
|
|||||||
types::GraphicRectangleAttributes* rectangle = shape.mutable_rectangle();
|
types::GraphicRectangleAttributes* rectangle = shape.mutable_rectangle();
|
||||||
PackVector2( *rectangle->mutable_top_left(), GetStart() );
|
PackVector2( *rectangle->mutable_top_left(), GetStart() );
|
||||||
PackVector2( *rectangle->mutable_bottom_right(), GetEnd() );
|
PackVector2( *rectangle->mutable_bottom_right(), GetEnd() );
|
||||||
|
rectangle->mutable_corner_radius()->set_value_nm( GetCornerRadius() );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,6 +284,7 @@ bool EDA_SHAPE::Deserialize( const google::protobuf::Any &aContainer )
|
|||||||
SetShape( SHAPE_T::RECTANGLE );
|
SetShape( SHAPE_T::RECTANGLE );
|
||||||
SetStart( UnpackVector2( shape.rectangle().top_left() ) );
|
SetStart( UnpackVector2( shape.rectangle().top_left() ) );
|
||||||
SetEnd( UnpackVector2( shape.rectangle().bottom_right() ) );
|
SetEnd( UnpackVector2( shape.rectangle().bottom_right() ) );
|
||||||
|
SetCornerRadius( shape.rectangle().corner_radius().value_nm() );
|
||||||
}
|
}
|
||||||
else if( shape.has_arc() )
|
else if( shape.has_arc() )
|
||||||
{
|
{
|
||||||
@ -432,6 +437,16 @@ int EDA_SHAPE::GetRectangleWidth() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int EDA_SHAPE::GetCornerRadius() const
|
||||||
|
{
|
||||||
|
return m_cornerRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EDA_SHAPE::SetCornerRadius( int aRadius )
|
||||||
|
{
|
||||||
|
m_cornerRadius = aRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_SHAPE::SetLength( const double& aLength )
|
void EDA_SHAPE::SetLength( const double& aLength )
|
||||||
{
|
{
|
||||||
@ -1800,17 +1815,38 @@ std::vector<SHAPE*> EDA_SHAPE::makeEffectiveShapes( bool aEdgeOnly, bool aLineCh
|
|||||||
|
|
||||||
case SHAPE_T::RECTANGLE:
|
case SHAPE_T::RECTANGLE:
|
||||||
{
|
{
|
||||||
std::vector<VECTOR2I> pts = GetRectCorners();
|
if( m_cornerRadius > 0 )
|
||||||
|
|
||||||
if( solidFill )
|
|
||||||
effectiveShapes.emplace_back( new SHAPE_SIMPLE( pts ) );
|
|
||||||
|
|
||||||
if( width > 0 || !solidFill )
|
|
||||||
{
|
{
|
||||||
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[0], pts[1], width ) );
|
ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ),
|
||||||
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[1], pts[2], width ) );
|
m_cornerRadius );
|
||||||
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], width ) );
|
SHAPE_POLY_SET poly;
|
||||||
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], width ) );
|
rr.TransformToPolygon( poly );
|
||||||
|
SHAPE_LINE_CHAIN outline = poly.Outline( 0 );
|
||||||
|
|
||||||
|
if( solidFill )
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SIMPLE( outline ) );
|
||||||
|
|
||||||
|
if( width > 0 || !solidFill )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < outline.PointCount() - 1; ++i )
|
||||||
|
effectiveShapes.emplace_back(
|
||||||
|
new SHAPE_SEGMENT( outline.CPoint( i ), outline.CPoint( i + 1 ), width ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<VECTOR2I> pts = GetRectCorners();
|
||||||
|
|
||||||
|
if( solidFill )
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SIMPLE( pts ) );
|
||||||
|
|
||||||
|
if( width > 0 || !solidFill )
|
||||||
|
{
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[0], pts[1], width ) );
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[1], pts[2], width ) );
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], width ) );
|
||||||
|
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], width ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2643,6 +2679,12 @@ static struct EDA_SHAPE_DESC
|
|||||||
shapeProps )
|
shapeProps )
|
||||||
.SetAvailableFunc( isRectangle );
|
.SetAvailableFunc( isRectangle );
|
||||||
|
|
||||||
|
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Corner Radius" ),
|
||||||
|
&EDA_SHAPE::SetCornerRadius, &EDA_SHAPE::GetCornerRadius,
|
||||||
|
PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::NOT_A_COORD ),
|
||||||
|
shapeProps )
|
||||||
|
.SetAvailableFunc( isRectangle );
|
||||||
|
|
||||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Line Width" ),
|
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Line Width" ),
|
||||||
&EDA_SHAPE::SetWidth, &EDA_SHAPE::GetWidth, PROPERTY_DISPLAY::PT_SIZE ),
|
&EDA_SHAPE::SetWidth, &EDA_SHAPE::GetWidth, PROPERTY_DISPLAY::PT_SIZE ),
|
||||||
shapeProps );
|
shapeProps );
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
#include <string_utils.h>
|
#include <string_utils.h>
|
||||||
#include <convert_basic_shapes_to_polygon.h>
|
#include <convert_basic_shapes_to_polygon.h>
|
||||||
|
#include <geometry/shape_rect.h>
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
@ -446,10 +447,21 @@ void DXF_PLOTTER::SetColor( const COLOR4D& color )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DXF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
|
void DXF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius )
|
||||||
{
|
{
|
||||||
wxASSERT( m_outputFile );
|
wxASSERT( m_outputFile );
|
||||||
|
|
||||||
|
if( aCornerRadius > 0 )
|
||||||
|
{
|
||||||
|
BOX2I box( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
|
||||||
|
box.Normalize();
|
||||||
|
SHAPE_RECT rect( box );
|
||||||
|
rect.SetRadius( aCornerRadius );
|
||||||
|
PlotPoly( rect.Outline(), fill, width, nullptr );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if( p1 != p2 )
|
if( p1 != p2 )
|
||||||
{
|
{
|
||||||
MoveTo( p1 );
|
MoveTo( p1 );
|
||||||
@ -605,6 +617,22 @@ void DXF_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DXF_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int aWidth,
|
||||||
|
void* aData )
|
||||||
|
{
|
||||||
|
std::vector<VECTOR2I> cornerList;
|
||||||
|
cornerList.reserve( aCornerList.PointCount() );
|
||||||
|
|
||||||
|
for( int ii = 0; ii < aCornerList.PointCount(); ii++ )
|
||||||
|
cornerList.emplace_back( aCornerList.CPoint( ii ) );
|
||||||
|
|
||||||
|
if( aCornerList.IsClosed() && cornerList.front() != cornerList.back() )
|
||||||
|
cornerList.emplace_back( aCornerList.CPoint( 0 ) );
|
||||||
|
|
||||||
|
PlotPoly( cornerList, aFill, aWidth, aData );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DXF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
|
void DXF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
|
||||||
{
|
{
|
||||||
wxASSERT( m_outputFile );
|
wxASSERT( m_outputFile );
|
||||||
@ -735,17 +763,17 @@ void DXF_PLOTTER::ThickRect( const VECTOR2I& p1, const VECTOR2I& p2, int width,
|
|||||||
{
|
{
|
||||||
VECTOR2I offsetp1( p1.x - width/2, p1.y - width/2 );
|
VECTOR2I offsetp1( p1.x - width/2, p1.y - width/2 );
|
||||||
VECTOR2I offsetp2( p2.x + width/2, p2.y + width/2 );
|
VECTOR2I offsetp2( p2.x + width/2, p2.y + width/2 );
|
||||||
Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH );
|
Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH, 0 );
|
||||||
|
|
||||||
offsetp1.x += width;
|
offsetp1.x += width;
|
||||||
offsetp1.y += width;
|
offsetp1.y += width;
|
||||||
offsetp2.x -= width;
|
offsetp2.x -= width;
|
||||||
offsetp2.y -= width;
|
offsetp2.y -= width;
|
||||||
Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH );
|
Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH, 0 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Rect( p1, p2, FILL_T::NO_FILL, DXF_LINE_WIDTH );
|
Rect( p1, p2, FILL_T::NO_FILL, DXF_LINE_WIDTH, 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <string_utils.h>
|
#include <string_utils.h>
|
||||||
#include <convert_basic_shapes_to_polygon.h>
|
#include <convert_basic_shapes_to_polygon.h>
|
||||||
|
#include <geometry/shape_rect.h>
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
@ -846,8 +847,19 @@ void GERBER_PLOTTER::PenTo( const VECTOR2I& aPos, char plume )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GERBER_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
|
void GERBER_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius )
|
||||||
{
|
{
|
||||||
|
if( aCornerRadius > 0 )
|
||||||
|
{
|
||||||
|
BOX2I box( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
|
||||||
|
box.Normalize();
|
||||||
|
SHAPE_RECT rect( box );
|
||||||
|
rect.SetRadius( aCornerRadius );
|
||||||
|
PlotPoly( rect.Outline(), fill, width, nullptr );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<VECTOR2I> cornerList;
|
std::vector<VECTOR2I> cornerList;
|
||||||
|
|
||||||
cornerList.reserve( 5 );
|
cornerList.reserve( 5 );
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
#include <plotters/plotters_pslike.h>
|
#include <plotters/plotters_pslike.h>
|
||||||
|
#include <geometry/shape_rect.h>
|
||||||
|
|
||||||
|
|
||||||
std::string PDF_PLOTTER::encodeStringForPlotter( const wxString& aText )
|
std::string PDF_PLOTTER::encodeStringForPlotter( const wxString& aText )
|
||||||
@ -227,7 +228,8 @@ void PDF_PLOTTER::SetDash( int aLineWidth, LINE_STYLE aLineStyle )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
|
void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius )
|
||||||
{
|
{
|
||||||
wxASSERT( m_workFile );
|
wxASSERT( m_workFile );
|
||||||
|
|
||||||
@ -236,6 +238,16 @@ void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int
|
|||||||
|
|
||||||
SetCurrentLineWidth( width );
|
SetCurrentLineWidth( width );
|
||||||
|
|
||||||
|
if( aCornerRadius > 0 )
|
||||||
|
{
|
||||||
|
BOX2I box( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
|
||||||
|
box.Normalize();
|
||||||
|
SHAPE_RECT rect( box );
|
||||||
|
rect.SetRadius( aCornerRadius );
|
||||||
|
PlotPoly( rect.Outline(), fill, width, nullptr );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
VECTOR2I size = p2 - p1;
|
VECTOR2I size = p2 - p1;
|
||||||
|
|
||||||
if( size.x == 0 && size.y == 0 )
|
if( size.x == 0 && size.y == 0 )
|
||||||
@ -429,6 +441,22 @@ void PDF_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PDF_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int aWidth,
|
||||||
|
void* aData )
|
||||||
|
{
|
||||||
|
std::vector<VECTOR2I> cornerList;
|
||||||
|
cornerList.reserve( aCornerList.PointCount() );
|
||||||
|
|
||||||
|
for( int ii = 0; ii < aCornerList.PointCount(); ii++ )
|
||||||
|
cornerList.emplace_back( aCornerList.CPoint( ii ) );
|
||||||
|
|
||||||
|
if( aCornerList.IsClosed() && cornerList.front() != cornerList.back() )
|
||||||
|
cornerList.emplace_back( aCornerList.CPoint( 0 ) );
|
||||||
|
|
||||||
|
PlotPoly( cornerList, aFill, aWidth, aData );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PDF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
|
void PDF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
|
||||||
{
|
{
|
||||||
wxASSERT( m_workFile );
|
wxASSERT( m_workFile );
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <convert_basic_shapes_to_polygon.h>
|
#include <convert_basic_shapes_to_polygon.h>
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
|
#include <geometry/shape_rect.h>
|
||||||
#include <string_utils.h>
|
#include <string_utils.h>
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
@ -457,13 +458,24 @@ void PS_PLOTTER::SetDash( int aLineWidth, LINE_STYLE aLineStyle )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PS_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
|
void PS_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius )
|
||||||
{
|
{
|
||||||
SetCurrentLineWidth( width );
|
SetCurrentLineWidth( width );
|
||||||
|
|
||||||
if( fill == FILL_T::NO_FILL && GetCurrentLineWidth() <= 0 )
|
if( fill == FILL_T::NO_FILL && GetCurrentLineWidth() <= 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if( aCornerRadius > 0 )
|
||||||
|
{
|
||||||
|
BOX2I box( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
|
||||||
|
box.Normalize();
|
||||||
|
SHAPE_RECT rect( box );
|
||||||
|
rect.SetRadius( aCornerRadius );
|
||||||
|
PlotPoly( rect.Outline(), fill, width, nullptr );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
VECTOR2D p1_dev = userToDeviceCoordinates( p1 );
|
VECTOR2D p1_dev = userToDeviceCoordinates( p1 );
|
||||||
VECTOR2D p2_dev = userToDeviceCoordinates( p2 );
|
VECTOR2D p2_dev = userToDeviceCoordinates( p2 );
|
||||||
|
|
||||||
@ -556,6 +568,22 @@ void PS_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFil
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PS_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int aWidth,
|
||||||
|
void* aData )
|
||||||
|
{
|
||||||
|
std::vector<VECTOR2I> cornerList;
|
||||||
|
cornerList.reserve( aCornerList.PointCount() );
|
||||||
|
|
||||||
|
for( int ii = 0; ii < aCornerList.PointCount(); ii++ )
|
||||||
|
cornerList.emplace_back( aCornerList.CPoint( ii ) );
|
||||||
|
|
||||||
|
if( aCornerList.IsClosed() && cornerList.front() != cornerList.back() )
|
||||||
|
cornerList.emplace_back( aCornerList.CPoint( 0 ) );
|
||||||
|
|
||||||
|
PlotPoly( cornerList, aFill, aWidth, aData );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PS_PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double aScaleFactor )
|
void PS_PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double aScaleFactor )
|
||||||
{
|
{
|
||||||
VECTOR2I pix_size; // size of the bitmap in pixels
|
VECTOR2I pix_size; // size of the bitmap in pixels
|
||||||
|
@ -372,7 +372,8 @@ void SVG_PLOTTER::SetDash( int aLineWidth, LINE_STYLE aLineStyle )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SVG_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
|
void SVG_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius )
|
||||||
{
|
{
|
||||||
BOX2I rect( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
|
BOX2I rect( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
|
||||||
rect.Normalize();
|
rect.Normalize();
|
||||||
@ -412,7 +413,7 @@ void SVG_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int
|
|||||||
rect_dev.GetPosition().y,
|
rect_dev.GetPosition().y,
|
||||||
rect_dev.GetSize().x,
|
rect_dev.GetSize().x,
|
||||||
rect_dev.GetSize().y,
|
rect_dev.GetSize().y,
|
||||||
0.0 /* radius of rounded corners */ );
|
userToDeviceSize( aCornerRadius ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ void PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double aSc
|
|||||||
end.x += size.x;
|
end.x += size.x;
|
||||||
end.y += size.y;
|
end.y += size.y;
|
||||||
|
|
||||||
Rect( start, end, FILL_T::NO_FILL, USE_DEFAULT_LINE_WIDTH );
|
Rect( start, end, FILL_T::NO_FILL, USE_DEFAULT_LINE_WIDTH, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -584,7 +584,7 @@ void PLOTTER::ThickArc( const EDA_SHAPE& aArcShape, void* aData, int aWidth )
|
|||||||
|
|
||||||
void PLOTTER::ThickRect( const VECTOR2I& p1, const VECTOR2I& p2, int width, void* aData )
|
void PLOTTER::ThickRect( const VECTOR2I& p1, const VECTOR2I& p2, int width, void* aData )
|
||||||
{
|
{
|
||||||
Rect( p1, p2, FILL_T::NO_FILL, width );
|
Rect( p1, p2, FILL_T::NO_FILL, width, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ void EDIT_POINTS::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
|
|||||||
};
|
};
|
||||||
|
|
||||||
for( const EDIT_POINT& point : m_points )
|
for( const EDIT_POINT& point : m_points )
|
||||||
drawPoint( point );
|
drawPoint( point, point.DrawCircle() );
|
||||||
|
|
||||||
for( const EDIT_LINE& line : m_lines )
|
for( const EDIT_LINE& line : m_lines )
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,8 @@
|
|||||||
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20240819 // Embedded Files - Update hash algorithm to Murmur3
|
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20240819 // Embedded Files - Update hash algorithm to Murmur3
|
||||||
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20241209 // Private flags for SCH_FIELDs
|
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20241209 // Private flags for SCH_FIELDs
|
||||||
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20250318 // ~ no longer means empty text
|
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20250318 // ~ no longer means empty text
|
||||||
#define SEXPR_SYMBOL_LIB_FILE_VERSION 20250324 // Jumper pin groups
|
//#define SEXPR_SYMBOL_LIB_FILE_VERSION 20250324 // Jumper pin groups
|
||||||
|
#define SEXPR_SYMBOL_LIB_FILE_VERSION 20250829 // Rounded Rectangles
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schematic file version.
|
* Schematic file version.
|
||||||
@ -124,4 +125,5 @@
|
|||||||
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250425 // uuids for tables
|
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250425 // uuids for tables
|
||||||
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250513 // Groups can have design block lib_id
|
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250513 // Groups can have design block lib_id
|
||||||
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250610 // DNP, etc. flags for rule areas
|
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250610 // DNP, etc. flags for rule areas
|
||||||
#define SEXPR_SCHEMATIC_FILE_VERSION 20250827 // Custom body styles
|
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250827 // Custom body styles
|
||||||
|
#define SEXPR_SCHEMATIC_FILE_VERSION 20250829 // Rounded Rectangles
|
||||||
|
@ -269,6 +269,9 @@ void formatRect( OUTPUTFORMATTER* aFormatter, EDA_SHAPE* aRect, bool aIsPrivate,
|
|||||||
aIsPrivate ? "private" : "",
|
aIsPrivate ? "private" : "",
|
||||||
formatIU( aRect->GetStart(), aInvertY ).c_str(),
|
formatIU( aRect->GetStart(), aInvertY ).c_str(),
|
||||||
formatIU( aRect->GetEnd(), aInvertY ).c_str() );
|
formatIU( aRect->GetEnd(), aInvertY ).c_str() );
|
||||||
|
if( aRect->GetCornerRadius() > 0 )
|
||||||
|
aFormatter->Print( "(radius %s)",
|
||||||
|
formatIU( aRect->GetCornerRadius() ).c_str() );
|
||||||
aStroke.Format( aFormatter, schIUScale );
|
aStroke.Format( aFormatter, schIUScale );
|
||||||
formatFill( aFormatter, aFillMode, aFillColor );
|
formatFill( aFormatter, aFillMode, aFillColor );
|
||||||
|
|
||||||
|
@ -1895,6 +1895,11 @@ SCH_SHAPE* SCH_IO_KICAD_SEXPR_PARSER::parseSymbolRectangle()
|
|||||||
NeedRIGHT();
|
NeedRIGHT();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_radius:
|
||||||
|
rectangle->SetCornerRadius( parseDouble( "corner radius" ) * schIUScale.IU_PER_MM );
|
||||||
|
NeedRIGHT();
|
||||||
|
break;
|
||||||
|
|
||||||
case T_stroke:
|
case T_stroke:
|
||||||
parseStroke( stroke );
|
parseStroke( stroke );
|
||||||
rectangle->SetStroke( stroke );
|
rectangle->SetStroke( stroke );
|
||||||
@ -4186,6 +4191,11 @@ SCH_SHAPE* SCH_IO_KICAD_SEXPR_PARSER::parseSchRectangle()
|
|||||||
NeedRIGHT();
|
NeedRIGHT();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_radius:
|
||||||
|
rectangle->SetCornerRadius( parseDouble( "corner radius" ) * schIUScale.IU_PER_MM );
|
||||||
|
NeedRIGHT();
|
||||||
|
break;
|
||||||
|
|
||||||
case T_stroke:
|
case T_stroke:
|
||||||
parseStroke( stroke );
|
parseStroke( stroke );
|
||||||
rectangle->SetStroke( stroke );
|
rectangle->SetStroke( stroke );
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#include <callback_gal.h>
|
#include <callback_gal.h>
|
||||||
#include <geometry/shape_segment.h>
|
#include <geometry/shape_segment.h>
|
||||||
#include <geometry/shape_rect.h>
|
#include <geometry/shape_rect.h>
|
||||||
|
#include <geometry/roundrect.h>
|
||||||
|
#include <geometry/shape_poly_set.h>
|
||||||
#include <geometry/shape_utils.h>
|
#include <geometry/shape_utils.h>
|
||||||
#include <gr_text.h>
|
#include <gr_text.h>
|
||||||
#include <sch_pin.h>
|
#include <sch_pin.h>
|
||||||
@ -1588,7 +1590,20 @@ void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer, bool aDimmed )
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SHAPE_T::RECTANGLE:
|
case SHAPE_T::RECTANGLE:
|
||||||
m_gal->DrawRectangle( shape->GetPosition(), shape->GetEnd() );
|
if( shape->GetCornerRadius() > 0 )
|
||||||
|
{
|
||||||
|
ROUNDRECT rr( SHAPE_RECT( shape->GetPosition(),
|
||||||
|
shape->GetRectangleWidth(),
|
||||||
|
shape->GetRectangleHeight() ),
|
||||||
|
shape->GetCornerRadius() );
|
||||||
|
SHAPE_POLY_SET poly;
|
||||||
|
rr.TransformToPolygon( poly );
|
||||||
|
m_gal->DrawPolygon( poly );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_gal->DrawRectangle( shape->GetPosition(), shape->GetEnd() );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SHAPE_T::POLY:
|
case SHAPE_T::POLY:
|
||||||
|
@ -462,7 +462,7 @@ bool SCH_PLOTTER::plotOneSheetPS( const wxString& aFileName, SCH_SCREEN* aScreen
|
|||||||
VECTOR2I end( actualPage.GetWidthIU( schIUScale.IU_PER_MILS ),
|
VECTOR2I end( actualPage.GetWidthIU( schIUScale.IU_PER_MILS ),
|
||||||
actualPage.GetHeightIU( schIUScale.IU_PER_MILS ) );
|
actualPage.GetHeightIU( schIUScale.IU_PER_MILS ) );
|
||||||
|
|
||||||
plotter->Rect( VECTOR2I( 0, 0 ), end, FILL_T::FILLED_SHAPE, 1.0 );
|
plotter->Rect( VECTOR2I( 0, 0 ), end, FILL_T::FILLED_SHAPE, 1.0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aPlotOpts.m_plotDrawingSheet )
|
if( aPlotOpts.m_plotDrawingSheet )
|
||||||
@ -639,7 +639,7 @@ bool SCH_PLOTTER::plotOneSheetSVG( const wxString& aFileName, SCH_SCREEN* aScree
|
|||||||
VECTOR2I end( actualPage.GetWidthIU( schIUScale.IU_PER_MILS ),
|
VECTOR2I end( actualPage.GetWidthIU( schIUScale.IU_PER_MILS ),
|
||||||
actualPage.GetHeightIU( schIUScale.IU_PER_MILS ) );
|
actualPage.GetHeightIU( schIUScale.IU_PER_MILS ) );
|
||||||
|
|
||||||
plotter->Rect( VECTOR2I( 0, 0 ), end, FILL_T::FILLED_SHAPE, 1.0 );
|
plotter->Rect( VECTOR2I( 0, 0 ), end, FILL_T::FILLED_SHAPE, 1.0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aPlotOpts.m_plotDrawingSheet )
|
if( aPlotOpts.m_plotDrawingSheet )
|
||||||
|
@ -274,7 +274,7 @@ void SCH_SHAPE::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS&
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SHAPE_T::RECTANGLE:
|
case SHAPE_T::RECTANGLE:
|
||||||
aPlotter->Rect( start, end, fill, pen_size );
|
aPlotter->Rect( start, end, fill, pen_size, GetCornerRadius() );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SHAPE_T::POLY:
|
case SHAPE_T::POLY:
|
||||||
|
@ -1222,14 +1222,14 @@ void SCH_SHEET::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS&
|
|||||||
if( aBackground && backgroundColor.a > 0.0 )
|
if( aBackground && backgroundColor.a > 0.0 )
|
||||||
{
|
{
|
||||||
aPlotter->SetColor( backgroundColor );
|
aPlotter->SetColor( backgroundColor );
|
||||||
aPlotter->Rect( m_pos, m_pos + m_size, FILL_T::FILLED_SHAPE, 1 );
|
aPlotter->Rect( m_pos, m_pos + m_size, FILL_T::FILLED_SHAPE, 1, 0 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
aPlotter->SetColor( borderColor );
|
aPlotter->SetColor( borderColor );
|
||||||
|
|
||||||
int penWidth = GetEffectivePenWidth( getRenderSettings( aPlotter ) );
|
int penWidth = GetEffectivePenWidth( getRenderSettings( aPlotter ) );
|
||||||
aPlotter->Rect( m_pos, m_pos + m_size, FILL_T::NO_FILL, penWidth );
|
aPlotter->Rect( m_pos, m_pos + m_size, FILL_T::NO_FILL, penWidth, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the sheet object a clickable hyperlink (e.g. for PDF plotter)
|
// Make the sheet object a clickable hyperlink (e.g. for PDF plotter)
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "sch_point_editor.h"
|
#include "sch_point_editor.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <ee_grid_helper.h>
|
#include <ee_grid_helper.h>
|
||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
#include <sch_commit.h>
|
#include <sch_commit.h>
|
||||||
@ -61,7 +62,7 @@ enum ARC_POINTS
|
|||||||
|
|
||||||
enum RECTANGLE_POINTS
|
enum RECTANGLE_POINTS
|
||||||
{
|
{
|
||||||
RECT_TOPLEFT, RECT_TOPRIGHT, RECT_BOTLEFT, RECT_BOTRIGHT, RECT_CENTER
|
RECT_TOPLEFT, RECT_RADIUS, RECT_TOPRIGHT, RECT_BOTLEFT, RECT_BOTRIGHT, RECT_CENTER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -391,6 +392,8 @@ public:
|
|||||||
VECTOR2I botRight = aRect.GetEnd();
|
VECTOR2I botRight = aRect.GetEnd();
|
||||||
|
|
||||||
aPoints.AddPoint( topLeft );
|
aPoints.AddPoint( topLeft );
|
||||||
|
aPoints.AddPoint( VECTOR2I( botRight.x - aRect.GetCornerRadius(), topLeft.y ) );
|
||||||
|
aPoints.Point( RECT_RADIUS ).SetDrawCircle();
|
||||||
aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
|
aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
|
||||||
aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
|
aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
|
||||||
aPoints.AddPoint( botRight );
|
aPoints.AddPoint( botRight );
|
||||||
@ -412,6 +415,7 @@ public:
|
|||||||
VECTOR2I botRight = aRect.GetEnd();
|
VECTOR2I botRight = aRect.GetEnd();
|
||||||
|
|
||||||
aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
|
aPoints.Point( RECT_TOPLEFT ).SetPosition( topLeft );
|
||||||
|
aPoints.Point( RECT_RADIUS ).SetPosition( VECTOR2I( botRight.x - aRect.GetCornerRadius(), topLeft.y ) );
|
||||||
aPoints.Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
|
aPoints.Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
|
||||||
aPoints.Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
|
aPoints.Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
|
||||||
aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
|
aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
|
||||||
@ -578,6 +582,16 @@ public:
|
|||||||
VECTOR2I moveVec = aPoints.Point( RECT_CENTER ).GetPosition() - oldBox.GetCenter();
|
VECTOR2I moveVec = aPoints.Point( RECT_CENTER ).GetPosition() - oldBox.GetCenter();
|
||||||
m_rect.Move( moveVec );
|
m_rect.Move( moveVec );
|
||||||
}
|
}
|
||||||
|
else if( isModified( aEditedPoint, aPoints.Point( RECT_RADIUS ) ) )
|
||||||
|
{
|
||||||
|
int width = std::abs( botRight.x - topLeft.x );
|
||||||
|
int height = std::abs( botRight.y - topLeft.y );
|
||||||
|
int maxRadius = std::min( width, height ) / 2;
|
||||||
|
int x = aPoints.Point( RECT_RADIUS ).GetX();
|
||||||
|
x = std::clamp( x, botRight.x - maxRadius, botRight.x );
|
||||||
|
aPoints.Point( RECT_RADIUS ).SetPosition( VECTOR2I( x, topLeft.y ) );
|
||||||
|
m_rect.SetCornerRadius( botRight.x - x );
|
||||||
|
}
|
||||||
else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
|
else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
|
||||||
{
|
{
|
||||||
oldSegs = KIGEOM::GetSegsInDirection( oldBox, DIRECTION_45::Directions::N );
|
oldSegs = KIGEOM::GetSegsInDirection( oldBox, DIRECTION_45::Directions::N );
|
||||||
|
@ -391,6 +391,9 @@ public:
|
|||||||
|
|
||||||
void SetRectangle( const long long int& aHeight, const long long int& aWidth );
|
void SetRectangle( const long long int& aHeight, const long long int& aWidth );
|
||||||
|
|
||||||
|
void SetCornerRadius( int aRadius );
|
||||||
|
int GetCornerRadius() const;
|
||||||
|
|
||||||
void SetSegmentAngle( const EDA_ANGLE& aAngle );
|
void SetSegmentAngle( const EDA_ANGLE& aAngle );
|
||||||
|
|
||||||
bool IsClockwiseArc() const;
|
bool IsClockwiseArc() const;
|
||||||
@ -496,6 +499,7 @@ protected:
|
|||||||
|
|
||||||
long long int m_rectangleHeight;
|
long long int m_rectangleHeight;
|
||||||
long long int m_rectangleWidth;
|
long long int m_rectangleWidth;
|
||||||
|
int m_cornerRadius;
|
||||||
|
|
||||||
double m_segmentLength;
|
double m_segmentLength;
|
||||||
EDA_ANGLE m_segmentAngle;
|
EDA_ANGLE m_segmentAngle;
|
||||||
|
@ -228,7 +228,8 @@ public:
|
|||||||
int GetPlotterArcHighDef() const { return m_IUsPerDecimil * 2; }
|
int GetPlotterArcHighDef() const { return m_IUsPerDecimil * 2; }
|
||||||
|
|
||||||
// Low level primitives
|
// Low level primitives
|
||||||
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width ) = 0;
|
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius = 0 ) = 0;
|
||||||
virtual void Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int width ) = 0;
|
virtual void Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int width ) = 0;
|
||||||
|
|
||||||
virtual void Arc( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd,
|
virtual void Arc( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd,
|
||||||
|
@ -84,7 +84,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
* DXF rectangle: fill not supported.
|
* DXF rectangle: fill not supported.
|
||||||
*/
|
*/
|
||||||
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width ) override;
|
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius = 0 ) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DXF circle: full functionality; it even does 'fills' drawing a
|
* DXF circle: full functionality; it even does 'fills' drawing a
|
||||||
@ -107,6 +108,9 @@ public:
|
|||||||
virtual void PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill,
|
virtual void PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill,
|
||||||
int aWidth, void* aData = nullptr ) override;
|
int aWidth, void* aData = nullptr ) override;
|
||||||
|
|
||||||
|
virtual void PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill,
|
||||||
|
int aWidth, void* aData = nullptr ) override;
|
||||||
|
|
||||||
virtual void ThickSegment( const VECTOR2I& start, const VECTOR2I& end, int width,
|
virtual void ThickSegment( const VECTOR2I& start, const VECTOR2I& end, int width,
|
||||||
void* aData ) override;
|
void* aData ) override;
|
||||||
|
|
||||||
|
@ -60,7 +60,8 @@ public:
|
|||||||
double aScale, bool aMirror ) override;
|
double aScale, bool aMirror ) override;
|
||||||
|
|
||||||
// Basic plot primitives
|
// Basic plot primitives
|
||||||
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width ) override;
|
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius = 0 ) override;
|
||||||
virtual void Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int width ) override;
|
virtual void Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int width ) override;
|
||||||
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||||
const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill, int aWidth ) override;
|
const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill, int aWidth ) override;
|
||||||
|
@ -185,7 +185,8 @@ public:
|
|||||||
|
|
||||||
virtual void SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil,
|
virtual void SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil,
|
||||||
double aScale, bool aMirror ) override;
|
double aScale, bool aMirror ) override;
|
||||||
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width ) override;
|
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius = 0 ) override;
|
||||||
virtual void Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int width ) override;
|
virtual void Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int width ) override;
|
||||||
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||||
const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill, int aWidth ) override;
|
const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill, int aWidth ) override;
|
||||||
@ -223,6 +224,9 @@ public:
|
|||||||
const KIFONT::METRICS& aFontMetrics,
|
const KIFONT::METRICS& aFontMetrics,
|
||||||
void* aData = nullptr ) override;
|
void* aData = nullptr ) override;
|
||||||
|
|
||||||
|
virtual void PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill,
|
||||||
|
int aWidth, void* aData = nullptr ) override;
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void emitSetRGBColor( double r, double g, double b, double a ) override;
|
virtual void emitSetRGBColor( double r, double g, double b, double a ) override;
|
||||||
@ -326,7 +330,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Rectangles in PDF. Supported by the native operator.
|
* Rectangles in PDF. Supported by the native operator.
|
||||||
*/
|
*/
|
||||||
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width ) override;
|
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius = 0 ) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Circle drawing for PDF. They're approximated by curves, but fill is supported
|
* Circle drawing for PDF. They're approximated by curves, but fill is supported
|
||||||
@ -346,6 +351,9 @@ public:
|
|||||||
virtual void PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill,
|
virtual void PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill,
|
||||||
int aWidth = USE_DEFAULT_LINE_WIDTH, void* aData = nullptr ) override;
|
int aWidth = USE_DEFAULT_LINE_WIDTH, void* aData = nullptr ) override;
|
||||||
|
|
||||||
|
virtual void PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill,
|
||||||
|
int aWidth = USE_DEFAULT_LINE_WIDTH, void* aData = nullptr ) override;
|
||||||
|
|
||||||
virtual void PenTo( const VECTOR2I& pos, char plume ) override;
|
virtual void PenTo( const VECTOR2I& pos, char plume ) override;
|
||||||
|
|
||||||
virtual void Text( const VECTOR2I& aPos,
|
virtual void Text( const VECTOR2I& aPos,
|
||||||
@ -572,7 +580,8 @@ public:
|
|||||||
|
|
||||||
virtual void SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil, double aScale,
|
virtual void SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil, double aScale,
|
||||||
bool aMirror ) override;
|
bool aMirror ) override;
|
||||||
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width ) override;
|
virtual void Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
|
||||||
|
int aCornerRadius = 0 ) override;
|
||||||
virtual void Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int width ) override;
|
virtual void Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int width ) override;
|
||||||
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||||
const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill,
|
const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill,
|
||||||
|
@ -54,6 +54,7 @@ public:
|
|||||||
m_position( aPoint ),
|
m_position( aPoint ),
|
||||||
m_isActive( false ),
|
m_isActive( false ),
|
||||||
m_isHover( false ),
|
m_isHover( false ),
|
||||||
|
m_drawCircle( false ),
|
||||||
m_gridConstraint( SNAP_TO_GRID ),
|
m_gridConstraint( SNAP_TO_GRID ),
|
||||||
m_snapConstraint( OBJECT_LAYERS ),
|
m_snapConstraint( OBJECT_LAYERS ),
|
||||||
m_connected( aConnected )
|
m_connected( aConnected )
|
||||||
@ -175,6 +176,9 @@ public:
|
|||||||
bool IsHover() const { return m_isHover; }
|
bool IsHover() const { return m_isHover; }
|
||||||
void SetHover( bool aHover = true ) { m_isHover = aHover; }
|
void SetHover( bool aHover = true ) { m_isHover = aHover; }
|
||||||
|
|
||||||
|
bool DrawCircle() const { return m_drawCircle; }
|
||||||
|
void SetDrawCircle( bool aDrawCircle = true ) { m_drawCircle = aDrawCircle; }
|
||||||
|
|
||||||
GRID_CONSTRAINT_TYPE GetGridConstraint() const { return m_gridConstraint; }
|
GRID_CONSTRAINT_TYPE GetGridConstraint() const { return m_gridConstraint; }
|
||||||
void SetGridConstraint( GRID_CONSTRAINT_TYPE aConstraint ) { m_gridConstraint = aConstraint; }
|
void SetGridConstraint( GRID_CONSTRAINT_TYPE aConstraint ) { m_gridConstraint = aConstraint; }
|
||||||
|
|
||||||
@ -201,6 +205,7 @@ private:
|
|||||||
VECTOR2I m_position; ///< Position of EDIT_POINT.
|
VECTOR2I m_position; ///< Position of EDIT_POINT.
|
||||||
bool m_isActive; ///< True if this point is being manipulated.
|
bool m_isActive; ///< True if this point is being manipulated.
|
||||||
bool m_isHover; ///< True if this point is being hovered over.
|
bool m_isHover; ///< True if this point is being hovered over.
|
||||||
|
bool m_drawCircle; ///< True if the point is drawn circular.
|
||||||
GRID_CONSTRAINT_TYPE m_gridConstraint; ///< Describe the grid snapping behavior.
|
GRID_CONSTRAINT_TYPE m_gridConstraint; ///< Describe the grid snapping behavior.
|
||||||
SNAP_CONSTRAINT_TYPE m_snapConstraint; ///< Describe the object snapping behavior.
|
SNAP_CONSTRAINT_TYPE m_snapConstraint; ///< Describe the object snapping behavior.
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <geometry/seg.h>
|
#include <geometry/seg.h>
|
||||||
#include <geometry/shape.h>
|
#include <geometry/shape.h>
|
||||||
#include <geometry/shape_line_chain.h>
|
#include <geometry/shape_line_chain.h>
|
||||||
|
#include <geometry/shape_poly_set.h>
|
||||||
#include <math/box2.h>
|
#include <math/box2.h>
|
||||||
#include <math/vector2d.h>
|
#include <math/vector2d.h>
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
@ -43,7 +44,8 @@ public:
|
|||||||
SHAPE_RECT() :
|
SHAPE_RECT() :
|
||||||
SHAPE( SH_RECT ),
|
SHAPE( SH_RECT ),
|
||||||
m_w( 0 ),
|
m_w( 0 ),
|
||||||
m_h( 0 )
|
m_h( 0 ),
|
||||||
|
m_radius( 0 )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +55,8 @@ public:
|
|||||||
SHAPE( SH_RECT ),
|
SHAPE( SH_RECT ),
|
||||||
m_p0( aBox.GetPosition() ),
|
m_p0( aBox.GetPosition() ),
|
||||||
m_w( aBox.GetWidth() ),
|
m_w( aBox.GetWidth() ),
|
||||||
m_h( aBox.GetHeight() )
|
m_h( aBox.GetHeight() ),
|
||||||
|
m_radius( 0 )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +66,8 @@ public:
|
|||||||
SHAPE( SH_RECT ),
|
SHAPE( SH_RECT ),
|
||||||
m_p0( aX0, aY0 ),
|
m_p0( aX0, aY0 ),
|
||||||
m_w( aW ),
|
m_w( aW ),
|
||||||
m_h( aH )
|
m_h( aH ),
|
||||||
|
m_radius( 0 )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,7 +77,8 @@ public:
|
|||||||
SHAPE( SH_RECT ),
|
SHAPE( SH_RECT ),
|
||||||
m_p0( aP0 ),
|
m_p0( aP0 ),
|
||||||
m_w( aW ),
|
m_w( aW ),
|
||||||
m_h( aH )
|
m_h( aH ),
|
||||||
|
m_radius( 0 )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,14 +88,16 @@ public:
|
|||||||
SHAPE( SH_RECT ),
|
SHAPE( SH_RECT ),
|
||||||
m_p0( aP0 ),
|
m_p0( aP0 ),
|
||||||
m_w( aP1.x - aP0.x ),
|
m_w( aP1.x - aP0.x ),
|
||||||
m_h( aP1.y - aP0.y )
|
m_h( aP1.y - aP0.y ),
|
||||||
|
m_radius( 0 )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SHAPE_RECT( const SHAPE_RECT& aOther ) :
|
SHAPE_RECT( const SHAPE_RECT& aOther ) :
|
||||||
SHAPE( SH_RECT ),
|
SHAPE( SH_RECT ),
|
||||||
m_p0( aOther.m_p0 ),
|
m_p0( aOther.m_p0 ),
|
||||||
m_w( aOther.m_w ),
|
m_w( aOther.m_w ),
|
||||||
m_h( aOther.m_h )
|
m_h( aOther.m_h ),
|
||||||
|
m_radius( aOther.m_radius )
|
||||||
{};
|
{};
|
||||||
|
|
||||||
SHAPE* Clone() const override
|
SHAPE* Clone() const override
|
||||||
@ -112,11 +119,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
SHAPE_RECT GetInflated( int aOffset ) const
|
SHAPE_RECT GetInflated( int aOffset ) const
|
||||||
{
|
{
|
||||||
return SHAPE_RECT{
|
SHAPE_RECT r{
|
||||||
m_p0 - VECTOR2I( aOffset, aOffset ),
|
m_p0 - VECTOR2I( aOffset, aOffset ),
|
||||||
m_w + 2 * aOffset,
|
m_w + 2 * aOffset,
|
||||||
m_h + 2 * aOffset,
|
m_h + 2 * aOffset,
|
||||||
};
|
};
|
||||||
|
r.SetRadius( m_radius + aOffset );
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,6 +195,19 @@ public:
|
|||||||
return m_h;
|
return m_h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the corner radius of the rectangle.
|
||||||
|
*/
|
||||||
|
int GetRadius() const
|
||||||
|
{
|
||||||
|
return m_radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRadius( int aRadius )
|
||||||
|
{
|
||||||
|
m_radius = aRadius;
|
||||||
|
}
|
||||||
|
|
||||||
void Move( const VECTOR2I& aVector ) override
|
void Move( const VECTOR2I& aVector ) override
|
||||||
{
|
{
|
||||||
m_p0 += aVector;
|
m_p0 += aVector;
|
||||||
@ -209,17 +231,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SHAPE_LINE_CHAIN Outline() const
|
const SHAPE_LINE_CHAIN Outline() const;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const std::string Format( bool aCplusPlus = true ) const override;
|
virtual const std::string Format( bool aCplusPlus = true ) const override;
|
||||||
|
|
||||||
@ -230,6 +242,7 @@ private:
|
|||||||
VECTOR2I m_p0; ///< Top-left corner
|
VECTOR2I m_p0; ///< Top-left corner
|
||||||
int m_w; ///< Width
|
int m_w; ///< Width
|
||||||
int m_h; ///< Height
|
int m_h; ///< Height
|
||||||
|
int m_radius; ///< Corner radius
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __SHAPE_RECT_H
|
#endif // __SHAPE_RECT_H
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <geometry/shape_rect.h>
|
#include <geometry/shape_rect.h>
|
||||||
#include <convert_basic_shapes_to_polygon.h>
|
#include <convert_basic_shapes_to_polygon.h>
|
||||||
|
#include <geometry/roundrect.h>
|
||||||
|
|
||||||
bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual, VECTOR2I* aLocation ) const
|
bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual, VECTOR2I* aLocation ) const
|
||||||
{
|
{
|
||||||
@ -114,6 +115,8 @@ const std::string SHAPE_RECT::Format( bool aCplusPlus ) const
|
|||||||
ss << m_w;
|
ss << m_w;
|
||||||
ss << ", ";
|
ss << ", ";
|
||||||
ss << m_h;
|
ss << m_h;
|
||||||
|
ss << ", ";
|
||||||
|
ss << m_radius;
|
||||||
ss << ");";
|
ss << ");";
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
@ -123,6 +126,13 @@ const std::string SHAPE_RECT::Format( bool aCplusPlus ) const
|
|||||||
void SHAPE_RECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
|
void SHAPE_RECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
|
||||||
ERROR_LOC aErrorLoc ) const
|
ERROR_LOC aErrorLoc ) const
|
||||||
{
|
{
|
||||||
|
if( m_radius > 0 )
|
||||||
|
{
|
||||||
|
ROUNDRECT rr( *this, m_radius );
|
||||||
|
rr.TransformToPolygon( aBuffer );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int idx = aBuffer.NewOutline();
|
int idx = aBuffer.NewOutline();
|
||||||
SHAPE_LINE_CHAIN& outline = aBuffer.Outline( idx );
|
SHAPE_LINE_CHAIN& outline = aBuffer.Outline( idx );
|
||||||
|
|
||||||
@ -132,3 +142,23 @@ void SHAPE_RECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
|
|||||||
outline.Append( { m_p0.x, m_p0.y + m_h } );
|
outline.Append( { m_p0.x, m_p0.y + m_h } );
|
||||||
outline.SetClosed( true );
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -964,6 +964,9 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_SHAPE* aShape ) const
|
|||||||
prefix.c_str(),
|
prefix.c_str(),
|
||||||
formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
|
formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
|
||||||
formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
|
formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
|
||||||
|
|
||||||
|
if( aShape->GetCornerRadius() > 0 )
|
||||||
|
m_out->Print( " (radius %s)", formatInternalUnits( aShape->GetCornerRadius() ).c_str() );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SHAPE_T::CIRCLE:
|
case SHAPE_T::CIRCLE:
|
||||||
@ -1801,6 +1804,9 @@ void PCB_IO_KICAD_SEXPR::format( const PAD* aPad ) const
|
|||||||
m_out->Print( "(gr_rect (start %s) (end %s)",
|
m_out->Print( "(gr_rect (start %s) (end %s)",
|
||||||
formatInternalUnits( primitive->GetStart() ).c_str(),
|
formatInternalUnits( primitive->GetStart() ).c_str(),
|
||||||
formatInternalUnits( primitive->GetEnd() ).c_str() );
|
formatInternalUnits( primitive->GetEnd() ).c_str() );
|
||||||
|
|
||||||
|
if( primitive->GetCornerRadius() > 0 )
|
||||||
|
m_out->Print( " (radius %s)", formatInternalUnits( primitive->GetCornerRadius() ).c_str() );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -186,7 +186,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl
|
|||||||
//#define SEXPR_BOARD_FILE_VERSION 20250513 // Groups can have design block lib_id
|
//#define SEXPR_BOARD_FILE_VERSION 20250513 // Groups can have design block lib_id
|
||||||
//#define SEXPR_BOARD_FILE_VERSION 20250801 // (island) -> (island yes/no)
|
//#define SEXPR_BOARD_FILE_VERSION 20250801 // (island) -> (island yes/no)
|
||||||
//#define SEXPR_BOARD_FILE_VERSION 20250811 // press-fit pad fabr prop support
|
//#define SEXPR_BOARD_FILE_VERSION 20250811 // press-fit pad fabr prop support
|
||||||
#define SEXPR_BOARD_FILE_VERSION 20250818 // Support for custom layer counts in footprints
|
//#define SEXPR_BOARD_FILE_VERSION 20250818 // Support for custom layer counts in footprints
|
||||||
|
#define SEXPR_BOARD_FILE_VERSION 20250829 // Support Rounded Rectangles
|
||||||
|
|
||||||
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
|
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
|
||||||
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting
|
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting
|
||||||
|
@ -3192,6 +3192,11 @@ PCB_SHAPE* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_SHAPE( BOARD_ITEM* aParent )
|
|||||||
NeedRIGHT();
|
NeedRIGHT();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_radius:
|
||||||
|
shape->SetCornerRadius( parseBoardUnits( "corner radius" ) );
|
||||||
|
NeedRIGHT();
|
||||||
|
break;
|
||||||
|
|
||||||
case T_stroke:
|
case T_stroke:
|
||||||
{
|
{
|
||||||
STROKE_PARAMS_PARSER strokeParser( reader, pcbIUScale.IU_PER_MM );
|
STROKE_PARAMS_PARSER strokeParser( reader, pcbIUScale.IU_PER_MM );
|
||||||
|
@ -63,6 +63,8 @@
|
|||||||
#include <geometry/geometry_utils.h>
|
#include <geometry/geometry_utils.h>
|
||||||
#include <geometry/shape_line_chain.h>
|
#include <geometry/shape_line_chain.h>
|
||||||
#include <geometry/shape_rect.h>
|
#include <geometry/shape_rect.h>
|
||||||
|
#include <geometry/shape_poly_set.h>
|
||||||
|
#include <geometry/roundrect.h>
|
||||||
#include <geometry/shape_segment.h>
|
#include <geometry/shape_segment.h>
|
||||||
#include <geometry/shape_simple.h>
|
#include <geometry/shape_simple.h>
|
||||||
#include <geometry/shape_circle.h>
|
#include <geometry/shape_circle.h>
|
||||||
@ -1973,50 +1975,97 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
|
|||||||
|
|
||||||
case SHAPE_T::RECTANGLE:
|
case SHAPE_T::RECTANGLE:
|
||||||
{
|
{
|
||||||
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
|
if( aShape->GetCornerRadius() > 0 )
|
||||||
|
{
|
||||||
|
ROUNDRECT rr( SHAPE_RECT( aShape->GetStart(), aShape->GetRectangleWidth(),
|
||||||
|
aShape->GetRectangleHeight() ),
|
||||||
|
aShape->GetCornerRadius() );
|
||||||
|
SHAPE_POLY_SET poly;
|
||||||
|
rr.TransformToPolygon( poly );
|
||||||
|
SHAPE_LINE_CHAIN outline = poly.Outline( 0 );
|
||||||
|
|
||||||
if( aShape->IsProxyItem() )
|
if( aShape->IsProxyItem() )
|
||||||
{
|
{
|
||||||
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||||
m_gal->DrawLine( pts[0], pts[1] );
|
m_gal->DrawPolygon( outline );
|
||||||
m_gal->DrawLine( pts[1], pts[2] );
|
}
|
||||||
m_gal->DrawLine( pts[2], pts[3] );
|
else if( outline_mode )
|
||||||
m_gal->DrawLine( pts[3], pts[0] );
|
{
|
||||||
m_gal->DrawLine( pts[0], pts[2] );
|
m_gal->DrawSegmentChain( outline, thickness );
|
||||||
m_gal->DrawLine( pts[1], pts[3] );
|
}
|
||||||
}
|
else
|
||||||
else if( outline_mode )
|
{
|
||||||
{
|
m_gal->SetIsFill( true );
|
||||||
m_gal->DrawSegment( pts[0], pts[1], thickness );
|
m_gal->SetIsStroke( false );
|
||||||
m_gal->DrawSegment( pts[1], pts[2], thickness );
|
|
||||||
m_gal->DrawSegment( pts[2], pts[3], thickness );
|
if( lineStyle == LINE_STYLE::SOLID && thickness > 0 )
|
||||||
m_gal->DrawSegment( pts[3], pts[0], thickness );
|
{
|
||||||
|
m_gal->DrawSegmentChain( outline, thickness );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( isSolidFill )
|
||||||
|
{
|
||||||
|
if( thickness < 0 )
|
||||||
|
{
|
||||||
|
SHAPE_POLY_SET deflated_shape = outline;
|
||||||
|
deflated_shape.Inflate( thickness / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS, m_maxError );
|
||||||
|
m_gal->DrawPolygon( deflated_shape );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_gal->DrawPolygon( outline );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_gal->SetIsFill( true );
|
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
|
||||||
m_gal->SetIsStroke( false );
|
|
||||||
|
|
||||||
if( lineStyle == LINE_STYLE::SOLID && thickness > 0 )
|
if( aShape->IsProxyItem() )
|
||||||
|
{
|
||||||
|
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||||
|
m_gal->DrawLine( pts[0], pts[1] );
|
||||||
|
m_gal->DrawLine( pts[1], pts[2] );
|
||||||
|
m_gal->DrawLine( pts[2], pts[3] );
|
||||||
|
m_gal->DrawLine( pts[3], pts[0] );
|
||||||
|
m_gal->DrawLine( pts[0], pts[2] );
|
||||||
|
m_gal->DrawLine( pts[1], pts[3] );
|
||||||
|
}
|
||||||
|
else if( outline_mode )
|
||||||
{
|
{
|
||||||
m_gal->DrawSegment( pts[0], pts[1], thickness );
|
m_gal->DrawSegment( pts[0], pts[1], thickness );
|
||||||
m_gal->DrawSegment( pts[1], pts[2], thickness );
|
m_gal->DrawSegment( pts[1], pts[2], thickness );
|
||||||
m_gal->DrawSegment( pts[2], pts[3], thickness );
|
m_gal->DrawSegment( pts[2], pts[3], thickness );
|
||||||
m_gal->DrawSegment( pts[3], pts[0], thickness );
|
m_gal->DrawSegment( pts[3], pts[0], thickness );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if( isSolidFill )
|
|
||||||
{
|
{
|
||||||
SHAPE_POLY_SET poly;
|
m_gal->SetIsFill( true );
|
||||||
poly.NewOutline();
|
m_gal->SetIsStroke( false );
|
||||||
|
|
||||||
for( const VECTOR2I& pt : pts )
|
if( lineStyle == LINE_STYLE::SOLID && thickness > 0 )
|
||||||
poly.Append( pt );
|
{
|
||||||
|
m_gal->DrawSegment( pts[0], pts[1], thickness );
|
||||||
|
m_gal->DrawSegment( pts[1], pts[2], thickness );
|
||||||
|
m_gal->DrawSegment( pts[2], pts[3], thickness );
|
||||||
|
m_gal->DrawSegment( pts[3], pts[0], thickness );
|
||||||
|
}
|
||||||
|
|
||||||
if( thickness < 0 )
|
if( isSolidFill )
|
||||||
poly.Inflate( thickness / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS, m_maxError );
|
{
|
||||||
|
SHAPE_POLY_SET poly;
|
||||||
|
poly.NewOutline();
|
||||||
|
|
||||||
m_gal->DrawPolygon( poly );
|
for( const VECTOR2I& pt : pts )
|
||||||
|
poly.Append( pt );
|
||||||
|
|
||||||
|
if( thickness < 0 )
|
||||||
|
poly.Inflate( thickness / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
|
||||||
|
m_maxError );
|
||||||
|
|
||||||
|
m_gal->DrawPolygon( poly );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1180,7 +1180,7 @@ static void FillNegativeKnockout( PLOTTER *aPlotter, const BOX2I &aBbbox )
|
|||||||
|
|
||||||
BOX2I area = aBbbox;
|
BOX2I area = aBbbox;
|
||||||
area.Inflate( margin );
|
area.Inflate( margin );
|
||||||
aPlotter->Rect( area.GetOrigin(), area.GetEnd(), FILL_T::FILLED_SHAPE, 0 );
|
aPlotter->Rect( area.GetOrigin(), area.GetEnd(), FILL_T::FILLED_SHAPE, 0, 0 );
|
||||||
aPlotter->SetColor( BLACK );
|
aPlotter->SetColor( BLACK );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <geometry/shape_circle.h>
|
#include <geometry/shape_circle.h>
|
||||||
#include <geometry/shape_line_chain.h> // for SHAPE_LINE_CHAIN
|
#include <geometry/shape_line_chain.h> // for SHAPE_LINE_CHAIN
|
||||||
#include <geometry/shape_poly_set.h> // for SHAPE_POLY_SET, SHAPE_P...
|
#include <geometry/shape_poly_set.h> // for SHAPE_POLY_SET, SHAPE_P...
|
||||||
|
#include <geometry/shape_rect.h>
|
||||||
#include <geometry/shape_segment.h>
|
#include <geometry/shape_segment.h>
|
||||||
#include <string_utils.h>
|
#include <string_utils.h>
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
@ -1081,19 +1082,28 @@ void BRDITEMS_PLOTTER::PlotShape( const PCB_SHAPE* aShape )
|
|||||||
|
|
||||||
case SHAPE_T::RECTANGLE:
|
case SHAPE_T::RECTANGLE:
|
||||||
{
|
{
|
||||||
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
|
int radius = aShape->GetCornerRadius();
|
||||||
|
|
||||||
if( m_plotter->GetPlotterType() == PLOT_FORMAT::DXF && GetDXFPlotMode() == SKETCH )
|
if( radius == 0 && m_plotter->GetPlotterType() == PLOT_FORMAT::DXF &&
|
||||||
|
GetDXFPlotMode() == SKETCH )
|
||||||
{
|
{
|
||||||
|
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
|
||||||
m_plotter->ThickRect( pts[0], pts[2], thickness, getMetadata() );
|
m_plotter->ThickRect( pts[0], pts[2], thickness, getMetadata() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SHAPE_POLY_SET poly;
|
BOX2I box( aShape->GetStart(), VECTOR2I( aShape->GetEnd().x - aShape->GetStart().x,
|
||||||
|
aShape->GetEnd().y - aShape->GetStart().y ) );
|
||||||
|
box.Normalize();
|
||||||
|
SHAPE_RECT rect( box );
|
||||||
|
rect.SetRadius( radius );
|
||||||
|
|
||||||
|
SHAPE_LINE_CHAIN outline = rect.Outline();
|
||||||
|
SHAPE_POLY_SET poly;
|
||||||
poly.NewOutline();
|
poly.NewOutline();
|
||||||
|
|
||||||
for( const VECTOR2I& pt : pts )
|
for( int ii = 0; ii < outline.PointCount() - 1; ++ii )
|
||||||
poly.Append( pt );
|
poly.Append( outline.CPoint( ii ) );
|
||||||
|
|
||||||
if( margin < 0 )
|
if( margin < 0 )
|
||||||
poly.Inflate( margin / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS, aShape->GetMaxError() );
|
poly.Inflate( margin / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS, aShape->GetMaxError() );
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
#include <advanced_config.h>
|
#include <advanced_config.h>
|
||||||
@ -68,6 +69,7 @@ const unsigned int PCB_POINT_EDITOR::COORDS_PADDING = pcbIUScale.mmToIU( 20 );
|
|||||||
enum RECT_POINTS
|
enum RECT_POINTS
|
||||||
{
|
{
|
||||||
RECT_TOP_LEFT,
|
RECT_TOP_LEFT,
|
||||||
|
RECT_RADIUS,
|
||||||
RECT_TOP_RIGHT,
|
RECT_TOP_RIGHT,
|
||||||
RECT_BOT_RIGHT,
|
RECT_BOT_RIGHT,
|
||||||
RECT_BOT_LEFT,
|
RECT_BOT_LEFT,
|
||||||
@ -137,6 +139,8 @@ public:
|
|||||||
std::swap( topLeft.y, botRight.y );
|
std::swap( topLeft.y, botRight.y );
|
||||||
|
|
||||||
aPoints.AddPoint( topLeft );
|
aPoints.AddPoint( topLeft );
|
||||||
|
aPoints.AddPoint( VECTOR2I( botRight.x - aRectangle.GetCornerRadius(), topLeft.y ) );
|
||||||
|
aPoints.Point( RECT_RADIUS ).SetDrawCircle();
|
||||||
aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
|
aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
|
||||||
aPoints.AddPoint( botRight );
|
aPoints.AddPoint( botRight );
|
||||||
aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
|
aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
|
||||||
@ -203,6 +207,16 @@ public:
|
|||||||
aPoints.Point( RECT_CENTER ).GetPosition() - aRectangle.GetCenter();
|
aPoints.Point( RECT_CENTER ).GetPosition() - aRectangle.GetCenter();
|
||||||
aRectangle.Move( moveVector );
|
aRectangle.Move( moveVector );
|
||||||
}
|
}
|
||||||
|
else if( isModified( aEditedPoint, aPoints.Point( RECT_RADIUS ) ) )
|
||||||
|
{
|
||||||
|
int width = std::abs( botRight.x - topLeft.x );
|
||||||
|
int height = std::abs( botRight.y - topLeft.y );
|
||||||
|
int maxRadius = std::min( width, height ) / 2;
|
||||||
|
int x = aPoints.Point( RECT_RADIUS ).GetX();
|
||||||
|
x = std::clamp( x, botRight.x - maxRadius, botRight.x );
|
||||||
|
aPoints.Point( RECT_RADIUS ).SetPosition( x, topLeft.y );
|
||||||
|
aRectangle.SetCornerRadius( botRight.x - x );
|
||||||
|
}
|
||||||
else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
|
else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
|
||||||
{
|
{
|
||||||
setTop( topLeft.y );
|
setTop( topLeft.y );
|
||||||
@ -246,6 +260,7 @@ public:
|
|||||||
std::swap( topLeft.y, botRight.y );
|
std::swap( topLeft.y, botRight.y );
|
||||||
|
|
||||||
aPoints.Point( RECT_TOP_LEFT ).SetPosition( topLeft );
|
aPoints.Point( RECT_TOP_LEFT ).SetPosition( topLeft );
|
||||||
|
aPoints.Point( RECT_RADIUS ).SetPosition( botRight.x - aRectangle.GetCornerRadius(), topLeft.y );
|
||||||
aPoints.Point( RECT_TOP_RIGHT ).SetPosition( botRight.x, topLeft.y );
|
aPoints.Point( RECT_TOP_RIGHT ).SetPosition( botRight.x, topLeft.y );
|
||||||
aPoints.Point( RECT_BOT_RIGHT ).SetPosition( botRight );
|
aPoints.Point( RECT_BOT_RIGHT ).SetPosition( botRight );
|
||||||
aPoints.Point( RECT_BOT_LEFT ).SetPosition( topLeft.x, botRight.y );
|
aPoints.Point( RECT_BOT_LEFT ).SetPosition( topLeft.x, botRight.y );
|
||||||
|
@ -80,6 +80,7 @@ set( QA_EESCHEMA_SRCS
|
|||||||
test_incremental_netlister.cpp
|
test_incremental_netlister.cpp
|
||||||
test_legacy_power_symbols.cpp
|
test_legacy_power_symbols.cpp
|
||||||
test_sch_commit.cpp
|
test_sch_commit.cpp
|
||||||
|
test_shape_corner_radius.cpp
|
||||||
test_sch_group.cpp
|
test_sch_group.cpp
|
||||||
test_pin_numbers.cpp
|
test_pin_numbers.cpp
|
||||||
test_sch_netclass.cpp
|
test_sch_netclass.cpp
|
||||||
|
36
qa/tests/eeschema/test_shape_corner_radius.cpp
Normal file
36
qa/tests/eeschema/test_shape_corner_radius.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <sch_shape.h>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( SCHShapeCornerRadius )
|
||||||
|
{
|
||||||
|
SCH_SHAPE shape( SHAPE_T::RECTANGLE, LAYER_NOTES );
|
||||||
|
shape.SetPosition( VECTOR2I( 0, 0 ) );
|
||||||
|
shape.SetEnd( VECTOR2I( 100, 100 ) );
|
||||||
|
shape.SetCornerRadius( 20 );
|
||||||
|
BOOST_CHECK_EQUAL( shape.GetCornerRadius(), 20 );
|
||||||
|
}
|
@ -51,6 +51,7 @@ set( QA_KIMATH_SRCS
|
|||||||
geometry/test_shape_line_chain.cpp
|
geometry/test_shape_line_chain.cpp
|
||||||
geometry/test_shape_line_chain_collision.cpp
|
geometry/test_shape_line_chain_collision.cpp
|
||||||
geometry/test_vector_utils.cpp
|
geometry/test_vector_utils.cpp
|
||||||
|
geometry/test_shape_rect_corner.cpp
|
||||||
|
|
||||||
math/test_box2.cpp
|
math/test_box2.cpp
|
||||||
math/test_matrix3x3.cpp
|
math/test_matrix3x3.cpp
|
||||||
|
34
qa/tests/libs/kimath/geometry/test_shape_rect_corner.cpp
Normal file
34
qa/tests/libs/kimath/geometry/test_shape_rect_corner.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <geometry/shape_rect.h>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( ShapeRectCornerRadius )
|
||||||
|
{
|
||||||
|
SHAPE_RECT rect( VECTOR2I( 0, 0 ), VECTOR2I( 10, 10 ) );
|
||||||
|
rect.SetRadius( 2 );
|
||||||
|
BOOST_CHECK_EQUAL( rect.GetRadius(), 2 );
|
||||||
|
}
|
@ -48,6 +48,7 @@ set( QA_PCBNEW_SRCS
|
|||||||
test_prettifier.cpp
|
test_prettifier.cpp
|
||||||
test_libeval_compiler.cpp
|
test_libeval_compiler.cpp
|
||||||
test_reference_image_load.cpp
|
test_reference_image_load.cpp
|
||||||
|
test_shape_corner_radius.cpp
|
||||||
test_pcb_grid_helper.cpp
|
test_pcb_grid_helper.cpp
|
||||||
test_save_load.cpp
|
test_save_load.cpp
|
||||||
test_tracks_cleaner.cpp
|
test_tracks_cleaner.cpp
|
||||||
|
36
qa/tests/pcbnew/test_shape_corner_radius.cpp
Normal file
36
qa/tests/pcbnew/test_shape_corner_radius.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <pcb_shape.h>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( PCBShapeCornerRadius )
|
||||||
|
{
|
||||||
|
PCB_SHAPE shape( nullptr, SHAPE_T::RECTANGLE );
|
||||||
|
shape.SetStart( VECTOR2I( 0, 0 ) );
|
||||||
|
shape.SetEnd( VECTOR2I( 1000, 1000 ) );
|
||||||
|
shape.SetCornerRadius( 200 );
|
||||||
|
BOOST_CHECK_EQUAL( shape.GetCornerRadius(), 200 );
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user