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 bottom_right = 2;
|
||||
kiapi.common.types.Distance corner_radius = 3;
|
||||
}
|
||||
|
||||
message GraphicArcAttributes
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <geometry/shape_simple.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/roundrect.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <macros.h>
|
||||
#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_rectangleHeight( 0 ),
|
||||
m_rectangleWidth( 0 ),
|
||||
m_cornerRadius( 0 ),
|
||||
m_segmentLength( 0 ),
|
||||
m_editState( 0 ),
|
||||
m_proxyItem( false )
|
||||
@ -73,6 +75,7 @@ EDA_SHAPE::EDA_SHAPE( const SHAPE& aShape ) :
|
||||
m_hatchingDirty( true ),
|
||||
m_rectangleHeight( 0 ),
|
||||
m_rectangleWidth( 0 ),
|
||||
m_cornerRadius( 0 ),
|
||||
m_segmentLength( 0 ),
|
||||
m_editState( 0 ),
|
||||
m_proxyItem( false )
|
||||
@ -188,6 +191,7 @@ void EDA_SHAPE::Serialize( google::protobuf::Any &aContainer ) const
|
||||
types::GraphicRectangleAttributes* rectangle = shape.mutable_rectangle();
|
||||
PackVector2( *rectangle->mutable_top_left(), GetStart() );
|
||||
PackVector2( *rectangle->mutable_bottom_right(), GetEnd() );
|
||||
rectangle->mutable_corner_radius()->set_value_nm( GetCornerRadius() );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -280,6 +284,7 @@ bool EDA_SHAPE::Deserialize( const google::protobuf::Any &aContainer )
|
||||
SetShape( SHAPE_T::RECTANGLE );
|
||||
SetStart( UnpackVector2( shape.rectangle().top_left() ) );
|
||||
SetEnd( UnpackVector2( shape.rectangle().bottom_right() ) );
|
||||
SetCornerRadius( shape.rectangle().corner_radius().value_nm() );
|
||||
}
|
||||
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 )
|
||||
{
|
||||
@ -1799,6 +1814,26 @@ std::vector<SHAPE*> EDA_SHAPE::makeEffectiveShapes( bool aEdgeOnly, bool aLineCh
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECTANGLE:
|
||||
{
|
||||
if( m_cornerRadius > 0 )
|
||||
{
|
||||
ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ),
|
||||
m_cornerRadius );
|
||||
SHAPE_POLY_SET poly;
|
||||
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();
|
||||
|
||||
@ -1812,6 +1847,7 @@ std::vector<SHAPE*> EDA_SHAPE::makeEffectiveShapes( bool aEdgeOnly, bool aLineCh
|
||||
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], width ) );
|
||||
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], width ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2643,6 +2679,12 @@ static struct EDA_SHAPE_DESC
|
||||
shapeProps )
|
||||
.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" ),
|
||||
&EDA_SHAPE::SetWidth, &EDA_SHAPE::GetWidth, PROPERTY_DISPLAY::PT_SIZE ),
|
||||
shapeProps );
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <macros.h>
|
||||
#include <string_utils.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <trigo.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 );
|
||||
|
||||
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 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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 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.y += width;
|
||||
offsetp2.x -= 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
|
||||
{
|
||||
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 <convert_basic_shapes_to_polygon.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <macros.h>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#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;
|
||||
|
||||
cornerList.reserve( 5 );
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include <plotters/plotters_pslike.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
|
||||
|
||||
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 );
|
||||
|
||||
@ -236,6 +238,16 @@ void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int
|
||||
|
||||
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;
|
||||
|
||||
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 )
|
||||
{
|
||||
wxASSERT( m_workFile );
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <macros.h>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <string_utils.h>
|
||||
#include <trigo.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 );
|
||||
|
||||
if( fill == FILL_T::NO_FILL && GetCurrentLineWidth() <= 0 )
|
||||
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 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 )
|
||||
{
|
||||
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 ) );
|
||||
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.GetSize().x,
|
||||
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.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 )
|
||||
{
|
||||
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 )
|
||||
drawPoint( point );
|
||||
drawPoint( point, point.DrawCircle() );
|
||||
|
||||
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 20241209 // Private flags for SCH_FIELDs
|
||||
//#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.
|
||||
@ -124,4 +125,5 @@
|
||||
//#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 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" : "",
|
||||
formatIU( aRect->GetStart(), 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 );
|
||||
formatFill( aFormatter, aFillMode, aFillColor );
|
||||
|
||||
|
@ -1895,6 +1895,11 @@ SCH_SHAPE* SCH_IO_KICAD_SEXPR_PARSER::parseSymbolRectangle()
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_radius:
|
||||
rectangle->SetCornerRadius( parseDouble( "corner radius" ) * schIUScale.IU_PER_MM );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_stroke:
|
||||
parseStroke( stroke );
|
||||
rectangle->SetStroke( stroke );
|
||||
@ -4186,6 +4191,11 @@ SCH_SHAPE* SCH_IO_KICAD_SEXPR_PARSER::parseSchRectangle()
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_radius:
|
||||
rectangle->SetCornerRadius( parseDouble( "corner radius" ) * schIUScale.IU_PER_MM );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_stroke:
|
||||
parseStroke( stroke );
|
||||
rectangle->SetStroke( stroke );
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include <callback_gal.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/roundrect.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/shape_utils.h>
|
||||
#include <gr_text.h>
|
||||
#include <sch_pin.h>
|
||||
@ -1588,7 +1590,20 @@ void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer, bool aDimmed )
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECTANGLE:
|
||||
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;
|
||||
|
||||
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 ),
|
||||
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 )
|
||||
@ -639,7 +639,7 @@ bool SCH_PLOTTER::plotOneSheetSVG( const wxString& aFileName, SCH_SCREEN* aScree
|
||||
VECTOR2I end( actualPage.GetWidthIU( 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 )
|
||||
|
@ -274,7 +274,7 @@ void SCH_SHAPE::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS&
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECTANGLE:
|
||||
aPlotter->Rect( start, end, fill, pen_size );
|
||||
aPlotter->Rect( start, end, fill, pen_size, GetCornerRadius() );
|
||||
break;
|
||||
|
||||
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 )
|
||||
{
|
||||
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
|
||||
{
|
||||
aPlotter->SetColor( borderColor );
|
||||
|
||||
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)
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "sch_point_editor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ee_grid_helper.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <sch_commit.h>
|
||||
@ -61,7 +62,7 @@ enum ARC_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();
|
||||
|
||||
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( topLeft.x, botRight.y ) );
|
||||
aPoints.AddPoint( botRight );
|
||||
@ -412,6 +415,7 @@ public:
|
||||
VECTOR2I botRight = aRect.GetEnd();
|
||||
|
||||
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_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
|
||||
aPoints.Point( RECT_BOTRIGHT ).SetPosition( botRight );
|
||||
@ -578,6 +582,16 @@ public:
|
||||
VECTOR2I moveVec = aPoints.Point( RECT_CENTER ).GetPosition() - oldBox.GetCenter();
|
||||
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 ) ) )
|
||||
{
|
||||
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 SetCornerRadius( int aRadius );
|
||||
int GetCornerRadius() const;
|
||||
|
||||
void SetSegmentAngle( const EDA_ANGLE& aAngle );
|
||||
|
||||
bool IsClockwiseArc() const;
|
||||
@ -496,6 +499,7 @@ protected:
|
||||
|
||||
long long int m_rectangleHeight;
|
||||
long long int m_rectangleWidth;
|
||||
int m_cornerRadius;
|
||||
|
||||
double m_segmentLength;
|
||||
EDA_ANGLE m_segmentAngle;
|
||||
|
@ -228,7 +228,8 @@ public:
|
||||
int GetPlotterArcHighDef() const { return m_IUsPerDecimil * 2; }
|
||||
|
||||
// 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 Arc( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd,
|
||||
|
@ -84,7 +84,8 @@ public:
|
||||
/**
|
||||
* 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
|
||||
@ -107,6 +108,9 @@ public:
|
||||
virtual void PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill,
|
||||
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,
|
||||
void* aData ) override;
|
||||
|
||||
|
@ -60,7 +60,8 @@ public:
|
||||
double aScale, bool aMirror ) override;
|
||||
|
||||
// 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 Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
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,
|
||||
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 Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill, int aWidth ) override;
|
||||
@ -223,6 +224,9 @@ public:
|
||||
const KIFONT::METRICS& aFontMetrics,
|
||||
void* aData = nullptr ) override;
|
||||
|
||||
virtual void PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill,
|
||||
int aWidth, void* aData = nullptr ) override;
|
||||
|
||||
|
||||
protected:
|
||||
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.
|
||||
*/
|
||||
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
|
||||
@ -346,6 +351,9 @@ public:
|
||||
virtual void PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFill,
|
||||
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 Text( const VECTOR2I& aPos,
|
||||
@ -572,7 +580,8 @@ public:
|
||||
|
||||
virtual void SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil, 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 Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aAngle, double aRadius, FILL_T aFill,
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
m_position( aPoint ),
|
||||
m_isActive( false ),
|
||||
m_isHover( false ),
|
||||
m_drawCircle( false ),
|
||||
m_gridConstraint( SNAP_TO_GRID ),
|
||||
m_snapConstraint( OBJECT_LAYERS ),
|
||||
m_connected( aConnected )
|
||||
@ -175,6 +176,9 @@ public:
|
||||
bool IsHover() const { return m_isHover; }
|
||||
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; }
|
||||
void SetGridConstraint( GRID_CONSTRAINT_TYPE aConstraint ) { m_gridConstraint = aConstraint; }
|
||||
|
||||
@ -201,6 +205,7 @@ private:
|
||||
VECTOR2I m_position; ///< Position of EDIT_POINT.
|
||||
bool m_isActive; ///< True if this point is being manipulated.
|
||||
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.
|
||||
SNAP_CONSTRAINT_TYPE m_snapConstraint; ///< Describe the object snapping behavior.
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <math/box2.h>
|
||||
#include <math/vector2d.h>
|
||||
#include <trigo.h>
|
||||
@ -43,7 +44,8 @@ public:
|
||||
SHAPE_RECT() :
|
||||
SHAPE( SH_RECT ),
|
||||
m_w( 0 ),
|
||||
m_h( 0 )
|
||||
m_h( 0 ),
|
||||
m_radius( 0 )
|
||||
{}
|
||||
|
||||
/**
|
||||
@ -53,7 +55,8 @@ public:
|
||||
SHAPE( SH_RECT ),
|
||||
m_p0( aBox.GetPosition() ),
|
||||
m_w( aBox.GetWidth() ),
|
||||
m_h( aBox.GetHeight() )
|
||||
m_h( aBox.GetHeight() ),
|
||||
m_radius( 0 )
|
||||
{}
|
||||
|
||||
/**
|
||||
@ -63,7 +66,8 @@ public:
|
||||
SHAPE( SH_RECT ),
|
||||
m_p0( aX0, aY0 ),
|
||||
m_w( aW ),
|
||||
m_h( aH )
|
||||
m_h( aH ),
|
||||
m_radius( 0 )
|
||||
{}
|
||||
|
||||
/**
|
||||
@ -73,7 +77,8 @@ public:
|
||||
SHAPE( SH_RECT ),
|
||||
m_p0( aP0 ),
|
||||
m_w( aW ),
|
||||
m_h( aH )
|
||||
m_h( aH ),
|
||||
m_radius( 0 )
|
||||
{}
|
||||
|
||||
/**
|
||||
@ -83,14 +88,16 @@ public:
|
||||
SHAPE( SH_RECT ),
|
||||
m_p0( aP0 ),
|
||||
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( SH_RECT ),
|
||||
m_p0( aOther.m_p0 ),
|
||||
m_w( aOther.m_w ),
|
||||
m_h( aOther.m_h )
|
||||
m_h( aOther.m_h ),
|
||||
m_radius( aOther.m_radius )
|
||||
{};
|
||||
|
||||
SHAPE* Clone() const override
|
||||
@ -112,11 +119,13 @@ public:
|
||||
*/
|
||||
SHAPE_RECT GetInflated( int aOffset ) const
|
||||
{
|
||||
return SHAPE_RECT{
|
||||
SHAPE_RECT r{
|
||||
m_p0 - VECTOR2I( aOffset, aOffset ),
|
||||
m_w + 2 * aOffset,
|
||||
m_h + 2 * aOffset,
|
||||
};
|
||||
r.SetRadius( m_radius + aOffset );
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,6 +195,19 @@ public:
|
||||
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
|
||||
{
|
||||
m_p0 += aVector;
|
||||
@ -209,17 +231,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
const SHAPE_LINE_CHAIN Outline() const;
|
||||
|
||||
virtual const std::string Format( bool aCplusPlus = true ) const override;
|
||||
|
||||
@ -230,6 +242,7 @@ private:
|
||||
VECTOR2I m_p0; ///< Top-left corner
|
||||
int m_w; ///< Width
|
||||
int m_h; ///< Height
|
||||
int m_radius; ///< Corner radius
|
||||
};
|
||||
|
||||
#endif // __SHAPE_RECT_H
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include <geometry/shape_rect.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
|
||||
{
|
||||
@ -114,6 +115,8 @@ const std::string SHAPE_RECT::Format( bool aCplusPlus ) const
|
||||
ss << m_w;
|
||||
ss << ", ";
|
||||
ss << m_h;
|
||||
ss << ", ";
|
||||
ss << m_radius;
|
||||
ss << ");";
|
||||
|
||||
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,
|
||||
ERROR_LOC aErrorLoc ) const
|
||||
{
|
||||
if( m_radius > 0 )
|
||||
{
|
||||
ROUNDRECT rr( *this, m_radius );
|
||||
rr.TransformToPolygon( aBuffer );
|
||||
return;
|
||||
}
|
||||
|
||||
int idx = aBuffer.NewOutline();
|
||||
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.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(),
|
||||
formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
|
||||
formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
|
||||
|
||||
if( aShape->GetCornerRadius() > 0 )
|
||||
m_out->Print( " (radius %s)", formatInternalUnits( aShape->GetCornerRadius() ).c_str() );
|
||||
break;
|
||||
|
||||
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)",
|
||||
formatInternalUnits( primitive->GetStart() ).c_str(),
|
||||
formatInternalUnits( primitive->GetEnd() ).c_str() );
|
||||
|
||||
if( primitive->GetCornerRadius() > 0 )
|
||||
m_out->Print( " (radius %s)", formatInternalUnits( primitive->GetCornerRadius() ).c_str() );
|
||||
}
|
||||
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 20250801 // (island) -> (island yes/no)
|
||||
//#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 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();
|
||||
break;
|
||||
|
||||
case T_radius:
|
||||
shape->SetCornerRadius( parseBoardUnits( "corner radius" ) );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_stroke:
|
||||
{
|
||||
STROKE_PARAMS_PARSER strokeParser( reader, pcbIUScale.IU_PER_MM );
|
||||
|
@ -63,6 +63,8 @@
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/roundrect.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/shape_simple.h>
|
||||
#include <geometry/shape_circle.h>
|
||||
@ -1972,6 +1974,51 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECTANGLE:
|
||||
{
|
||||
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() )
|
||||
{
|
||||
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||
m_gal->DrawPolygon( outline );
|
||||
}
|
||||
else if( outline_mode )
|
||||
{
|
||||
m_gal->DrawSegmentChain( outline, thickness );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gal->SetIsFill( true );
|
||||
m_gal->SetIsStroke( false );
|
||||
|
||||
if( lineStyle == LINE_STYLE::SOLID && thickness > 0 )
|
||||
{
|
||||
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
|
||||
{
|
||||
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
|
||||
|
||||
@ -2014,11 +2061,13 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
|
||||
poly.Append( pt );
|
||||
|
||||
if( thickness < 0 )
|
||||
poly.Inflate( thickness / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS, m_maxError );
|
||||
poly.Inflate( thickness / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
|
||||
m_maxError );
|
||||
|
||||
m_gal->DrawPolygon( poly );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1180,7 +1180,7 @@ static void FillNegativeKnockout( PLOTTER *aPlotter, const BOX2I &aBbbox )
|
||||
|
||||
BOX2I area = aBbbox;
|
||||
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 );
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <geometry/shape_circle.h>
|
||||
#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_rect.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <string_utils.h>
|
||||
#include <macros.h>
|
||||
@ -1081,19 +1082,28 @@ void BRDITEMS_PLOTTER::PlotShape( const PCB_SHAPE* aShape )
|
||||
|
||||
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() );
|
||||
}
|
||||
else
|
||||
{
|
||||
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();
|
||||
|
||||
for( const VECTOR2I& pt : pts )
|
||||
poly.Append( pt );
|
||||
for( int ii = 0; ii < outline.PointCount() - 1; ++ii )
|
||||
poly.Append( outline.CPoint( ii ) );
|
||||
|
||||
if( margin < 0 )
|
||||
poly.Inflate( margin / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS, aShape->GetMaxError() );
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std::placeholders;
|
||||
#include <advanced_config.h>
|
||||
@ -68,6 +69,7 @@ const unsigned int PCB_POINT_EDITOR::COORDS_PADDING = pcbIUScale.mmToIU( 20 );
|
||||
enum RECT_POINTS
|
||||
{
|
||||
RECT_TOP_LEFT,
|
||||
RECT_RADIUS,
|
||||
RECT_TOP_RIGHT,
|
||||
RECT_BOT_RIGHT,
|
||||
RECT_BOT_LEFT,
|
||||
@ -137,6 +139,8 @@ public:
|
||||
std::swap( topLeft.y, botRight.y );
|
||||
|
||||
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( botRight );
|
||||
aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
|
||||
@ -203,6 +207,16 @@ public:
|
||||
aPoints.Point( RECT_CENTER ).GetPosition() - aRectangle.GetCenter();
|
||||
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 ) ) )
|
||||
{
|
||||
setTop( topLeft.y );
|
||||
@ -246,6 +260,7 @@ public:
|
||||
std::swap( topLeft.y, botRight.y );
|
||||
|
||||
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_BOT_RIGHT ).SetPosition( botRight );
|
||||
aPoints.Point( RECT_BOT_LEFT ).SetPosition( topLeft.x, botRight.y );
|
||||
|
@ -80,6 +80,7 @@ set( QA_EESCHEMA_SRCS
|
||||
test_incremental_netlister.cpp
|
||||
test_legacy_power_symbols.cpp
|
||||
test_sch_commit.cpp
|
||||
test_shape_corner_radius.cpp
|
||||
test_sch_group.cpp
|
||||
test_pin_numbers.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_collision.cpp
|
||||
geometry/test_vector_utils.cpp
|
||||
geometry/test_shape_rect_corner.cpp
|
||||
|
||||
math/test_box2.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_libeval_compiler.cpp
|
||||
test_reference_image_load.cpp
|
||||
test_shape_corner_radius.cpp
|
||||
test_pcb_grid_helper.cpp
|
||||
test_save_load.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