From 1e272ca21b2fd0ed34bb5e9710b607fb418a7f08 Mon Sep 17 00:00:00 2001 From: John Beard Date: Tue, 2 Sep 2025 16:57:21 +0800 Subject: [PATCH] Geom: use SHAPE_SEGMENT for OVAL OVAL didn't do anything SHAPE_SEGMENT couldn't already do. --- libs/kimath/include/geometry/oval.h | 83 +++----------------- libs/kimath/include/geometry/shape_segment.h | 20 +++++ libs/kimath/src/geometry/oval.cpp | 47 ++--------- libs/kimath/src/geometry/shape_segment.cpp | 25 ++++++ pcbnew/tools/item_modification_routine.cpp | 2 +- pcbnew/tools/pcb_grid_helper.cpp | 6 +- qa/tests/libs/kimath/geometry/test_oval.cpp | 2 +- 7 files changed, 66 insertions(+), 119 deletions(-) diff --git a/libs/kimath/include/geometry/oval.h b/libs/kimath/include/geometry/oval.h index a98f5e4ade..7ae68bb75b 100644 --- a/libs/kimath/include/geometry/oval.h +++ b/libs/kimath/include/geometry/oval.h @@ -25,86 +25,22 @@ #include -#include -#include -#include -#include #include -#include - - -class SHAPE_LINE_CHAIN; +#include /** - * Class that represents an oval shape (rectangle with semicircular end caps) + * @file Utility functions for ovals (oblongs/stadiums) * - * This is not a full-blown SHAPE (yet), but can be used for some simple - * purposes, as well as for type-based logic. + * An "oval" is represented by SHAPE_SEGMENT, but these functions + * aren't required for most users of SHAPE_SEGMENT. */ -class OVAL -{ -public: - /** - * Create an oval from the segment joining the centers of the semicircles - * and the diameter of the semicircles. - */ - OVAL( const SEG& aSeg, int aWidth ); - /** - * Create an oval from the overall size, the center of the oval, and the rotation. - * - * The shorter dimension is the width of the semicircles. - */ - OVAL( const VECTOR2I& aOverallSize, const VECTOR2I& aCenter, const EDA_ANGLE& aRotation ); - - /** - * Get the bounding box of the oval - */ - BOX2I BBox( int aClearance ) const; - - /** - * Get the width of the oval (diameter of the semicircles) - */ - int GetWidth() const { return m_width; } - - /** - * Get the overall length of the oval from endcap tip to endcap tip - */ - int GetLength() const { return m_seg.Length() + m_width; } - - /** - * Get the side length of the oval (=length between the centers of the semicircles) - */ - int GetSideLength() const { return m_seg.Length(); } - - /** - * Get the center point of the oval. - */ - VECTOR2I GetCenter() const { return m_seg.Center(); } - - /** - * Get the central segment of the oval - * - * (Endpoint are the centers of the semicircles) - */ - const SEG& GetSegment() const { return m_seg; } - - /** - * Get the angle of the oval's central segment. - * - * The direction is aligned with the segment start/end - */ - EDA_ANGLE GetAngle() const { return EDA_ANGLE( m_seg.B - m_seg.A ); } - -private: - SEG m_seg; - int m_width; -}; +class SHAPE_LINE_CHAIN; namespace KIGEOM { -SHAPE_LINE_CHAIN ConvertToChain( const OVAL& aOval ); +SHAPE_LINE_CHAIN ConvertToChain( const SHAPE_SEGMENT& aOval ); enum OVAL_KEY_POINTS @@ -129,12 +65,11 @@ using OVAL_KEY_POINT_FLAGS = unsigned int; * - The tips of the end caps * - The extreme cardinal points of the whole oval (if rotated non-cardinally) * - * @param aOvalSize - The size of the oval (overall length and width) - * @param aRotation - The rotation of the oval + * @param aOval - The oval to get the points from * @param aFlags - The flags indicating which points to return * * @return std::vector - The list of points and their geomtrical types */ -std::vector GetOvalKeyPoints( const OVAL& aOval, OVAL_KEY_POINT_FLAGS aFlags ); +std::vector GetOvalKeyPoints( const SHAPE_SEGMENT& aOval, OVAL_KEY_POINT_FLAGS aFlags ); -} // namespace KIGEOM \ No newline at end of file +} // namespace KIGEOM diff --git a/libs/kimath/include/geometry/shape_segment.h b/libs/kimath/include/geometry/shape_segment.h index 360864d866..7cd07a46bf 100644 --- a/libs/kimath/include/geometry/shape_segment.h +++ b/libs/kimath/include/geometry/shape_segment.h @@ -54,6 +54,8 @@ public: m_width( aWidth ) {}; + static SHAPE_SEGMENT BySizeAndCenter( const VECTOR2I& aSize, const VECTOR2I& aCenter, const EDA_ANGLE& aRotation ); + ~SHAPE_SEGMENT() {}; SHAPE* Clone() const override @@ -140,6 +142,24 @@ public: return m_width; } + /** + * Get the total length of the segment, from tip to tip. + */ + int GetTotalLength() const + { + return m_seg.Length() + m_width; + } + + VECTOR2I GetCenter() const + { + return m_seg.Center(); + } + + EDA_ANGLE GetAngle() const + { + return EDA_ANGLE( m_seg.B - m_seg.A ); + } + bool IsSolid() const override { return true; diff --git a/libs/kimath/src/geometry/oval.cpp b/libs/kimath/src/geometry/oval.cpp index 84c91373d6..916c1337dc 100644 --- a/libs/kimath/src/geometry/oval.cpp +++ b/libs/kimath/src/geometry/oval.cpp @@ -27,48 +27,14 @@ #include // for RotatePoint #include -#include #include using namespace KIGEOM; -OVAL::OVAL( const SEG& aSeg, int aWidth ) : m_seg( aSeg ), m_width( aWidth ) + +SHAPE_LINE_CHAIN KIGEOM::ConvertToChain( const SHAPE_SEGMENT& aOval ) { - // A negative width is meaningless - wxASSERT( aWidth > 0 ); -} - -OVAL::OVAL( const VECTOR2I& aOverallSize, const VECTOR2I& aCenter, const EDA_ANGLE& aRotation ) -{ - VECTOR2I segVec{}; - - // Find the major axis, without endcaps - if( aOverallSize.x > aOverallSize.y ) - segVec.x = ( aOverallSize.x - aOverallSize.y ); - else - segVec.y = ( aOverallSize.y - aOverallSize.x ); - - RotatePoint( segVec, aRotation ); - - m_seg = SEG( aCenter - segVec / 2, aCenter + segVec / 2 ); - m_width = std::min( aOverallSize.x, aOverallSize.y ); -} - - -BOX2I OVAL::BBox( int aClearance ) const -{ - const int rad = m_width / 2 + aClearance; - - const VECTOR2I& topleft = LexicographicalMin( m_seg.A, m_seg.B ); - const VECTOR2I& bottomright = LexicographicalMax( m_seg.A, m_seg.B ); - - return BOX2I::ByCorners( topleft - VECTOR2I( rad, rad ), bottomright + VECTOR2I( rad, rad ) ); -} - - -SHAPE_LINE_CHAIN KIGEOM::ConvertToChain( const OVAL& aOval ) -{ - const SEG& seg = aOval.GetSegment(); + const SEG& seg = aOval.GetSeg(); const VECTOR2I perp = GetRotated( seg.B - seg.A, ANGLE_90 ).Resize( aOval.GetWidth() / 2 ); SHAPE_LINE_CHAIN chain; @@ -81,11 +47,10 @@ SHAPE_LINE_CHAIN KIGEOM::ConvertToChain( const OVAL& aOval ) } -std::vector KIGEOM::GetOvalKeyPoints( const OVAL& aOval, - OVAL_KEY_POINT_FLAGS aFlags ) +std::vector KIGEOM::GetOvalKeyPoints( const SHAPE_SEGMENT& aOval, OVAL_KEY_POINT_FLAGS aFlags ) { const int half_width = aOval.GetWidth() / 2; - const int half_len = aOval.GetLength() / 2; + const int half_len = aOval.GetTotalLength() / 2; const EDA_ANGLE rotation = aOval.GetAngle() - ANGLE_90; // Points on a non-rotated pad at the origin, long-axis is y @@ -194,4 +159,4 @@ std::vector KIGEOM::GetOvalKeyPoints( const OVAL& aOval, } return pts; -} \ No newline at end of file +} diff --git a/libs/kimath/src/geometry/shape_segment.cpp b/libs/kimath/src/geometry/shape_segment.cpp index dc106a9b11..5519f8dc56 100644 --- a/libs/kimath/src/geometry/shape_segment.cpp +++ b/libs/kimath/src/geometry/shape_segment.cpp @@ -29,6 +29,31 @@ #include #include + +SHAPE_SEGMENT SHAPE_SEGMENT::BySizeAndCenter( const VECTOR2I& aOverallSize, const VECTOR2I& aCenter, + const EDA_ANGLE& aRotation ) +{ + VECTOR2I segVec{ 0, 0 }; + int width; + + // Find the major axis, without endcaps + if( aOverallSize.x > aOverallSize.y ) + { + width = aOverallSize.y; + segVec.x = aOverallSize.x - width; + } + else + { + width = aOverallSize.x; + segVec.y = aOverallSize.y - width; + } + + RotatePoint( segVec, aRotation ); + + return SHAPE_SEGMENT( aCenter - segVec / 2, aCenter + segVec / 2, width ); +} + + const std::string SHAPE_SEGMENT::Format( bool aCplusPlus ) const { std::stringstream ss; diff --git a/pcbnew/tools/item_modification_routine.cpp b/pcbnew/tools/item_modification_routine.cpp index fadfbf9dbb..a4e359b366 100644 --- a/pcbnew/tools/item_modification_routine.cpp +++ b/pcbnew/tools/item_modification_routine.cpp @@ -933,7 +933,7 @@ void OUTSET_ROUTINE::ProcessItem( BOARD_ITEM& aItem ) if( m_params.roundCorners ) { - const OVAL oval( seg, m_params.outsetDistance * 2 ); + const SHAPE_SEGMENT oval( seg, m_params.outsetDistance * 2 ); addChain( KIGEOM::ConvertToChain( oval ) ); } else diff --git a/pcbnew/tools/pcb_grid_helper.cpp b/pcbnew/tools/pcb_grid_helper.cpp index 9298cf4a98..4a04e3495f 100644 --- a/pcbnew/tools/pcb_grid_helper.cpp +++ b/pcbnew/tools/pcb_grid_helper.cpp @@ -1204,7 +1204,8 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos } case PAD_SHAPE::OVAL: { - const OVAL oval( aPad->GetSize( aLayer ), aPad->GetPosition(), aPad->GetOrientation() ); + const SHAPE_SEGMENT oval = SHAPE_SEGMENT::BySizeAndCenter( + aPad->GetSize( aLayer ), aPad->GetPosition(), aPad->GetOrientation() ); for( const TYPED_POINT2I& pt : KIGEOM::GetOvalKeyPoints( oval, ovalKeyPointFlags ) ) addAnchor( pt.m_point, OUTLINE | SNAPPABLE, aPad, pt.m_types ); @@ -1281,7 +1282,8 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos // For now there's no way to have an off-angle hole, so this is the // same as the pad. In future, this may not be true: // https://gitlab.com/kicad/code/kicad/-/issues/4124 - const OVAL oval( hole_size, hole_pos, aPad->GetOrientation() ); + const SHAPE_SEGMENT oval = + SHAPE_SEGMENT::BySizeAndCenter( hole_size, hole_pos, aPad->GetOrientation() ); snap_pts = KIGEOM::GetOvalKeyPoints( oval, ovalKeyPointFlags ); } diff --git a/qa/tests/libs/kimath/geometry/test_oval.cpp b/qa/tests/libs/kimath/geometry/test_oval.cpp index 0420540681..71defef774 100644 --- a/qa/tests/libs/kimath/geometry/test_oval.cpp +++ b/qa/tests/libs/kimath/geometry/test_oval.cpp @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_SUITE( Oval ) struct OVAL_POINTS_TEST_CASE { - OVAL m_oval; + SHAPE_SEGMENT m_oval; std::vector m_expected_points; };