43bool SegmentsShareEndpoint(
const SEG& aSegA,
const SEG& aSegB )
45 return ( aSegA.
A == aSegB.
A || aSegA.
A == aSegB.
B || aSegA.
B == aSegB.
A || aSegA.
B == aSegB.
B );
49std::pair<VECTOR2I*, VECTOR2I*> GetSharedEndpoints(
SEG& aSegA,
SEG& aSegB )
51 std::pair<VECTOR2I*, VECTOR2I*> result = {
nullptr,
nullptr };
53 if( aSegA.
A == aSegB.
A )
55 result = { &aSegA.
A, &aSegB.
A };
57 else if( aSegA.
A == aSegB.
B )
59 result = { &aSegA.
A, &aSegB.
B };
61 else if( aSegA.
B == aSegB.
A )
63 result = { &aSegA.
B, &aSegB.
A };
65 else if( aSegA.
B == aSegB.
B )
67 result = { &aSegA.
B, &aSegB.
B };
77 const std::optional<SEG>& aSeg )
79 wxASSERT_MSG( aLine.
GetShape() == SHAPE_T::SEGMENT,
"Can only modify segments" );
81 const bool removed = !aSeg.has_value() || aSeg->Length() == 0;
102 return _(
"Fillet Lines" );
110 return _(
"Unable to fillet the selected lines." );
114 return _(
"Some of the lines could not be filleted." );
128 auto [a_pt, b_pt] = GetSharedEndpoints( seg_a, seg_b );
145 VECTOR2I segToVec = aSegment.NearestPoint( aVecToTest ) - aVecToTest;
150 aPointToSet.
x = aVecToTest.x;
151 aPointToSet.
y = aVecToTest.y;
159 if( !setIfPointOnSeg( t1newPoint, seg_a, sArc.
GetP0() )
160 && !setIfPointOnSeg( t2newPoint, seg_b, sArc.
GetP0() ) )
166 if( !setIfPointOnSeg( t1newPoint, seg_a, sArc.
GetP1() )
167 && !setIfPointOnSeg( t2newPoint, seg_b, sArc.
GetP1() ) )
173 auto tArc = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
178 tArc->SetWidth( aLineA.
GetWidth() );
179 tArc->SetLayer( aLineA.
GetLayer() );
180 tArc->SetLocked( aLineA.
IsLocked() );
197 return _(
"Chamfer Lines" );
205 return _(
"Unable to chamfer the selected lines." );
209 return _(
"Some of the lines could not be chamfered." );
226 if( !SegmentsShareEndpoint( seg_a, seg_b ) )
232 std::optional<CHAMFER_RESULT> chamfer_result =
235 if( !chamfer_result )
241 auto tSegment = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
243 tSegment->SetStart( chamfer_result->m_chamfer.A );
244 tSegment->SetEnd( chamfer_result->m_chamfer.B );
247 tSegment->SetWidth( aLineA.
GetWidth() );
248 tSegment->SetLayer( aLineA.
GetLayer() );
249 tSegment->SetLocked( aLineA.
IsLocked() );
264 return _(
"Dogbone Corners" );
274 msg +=
_(
"Unable to add dogbone corners to the selected lines." );
278 msg +=
_(
"Some of the lines could not have dogbone corners added." );
286 msg +=
_(
"Some of the dogbone corners are too narrow to fit a "
287 "cutter of the specified radius." );
290 msg +=
_(
" Consider enabling the 'Add Slots' option." );
292 msg +=
_(
" Slots were added." );
310 auto [a_pt, b_pt] = GetSharedEndpoints( seg_a, seg_b );
324 std::optional<DOGBONE_RESULT> dogbone_result =
327 if( !dogbone_result )
333 if( dogbone_result->m_small_arc_mouth )
341 auto tArc = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
343 const auto copyProps = [&](
PCB_SHAPE& aShape )
345 aShape.SetWidth( aLineA.
GetWidth() );
346 aShape.SetLayer( aLineA.
GetLayer() );
347 aShape.SetLocked( aLineA.
IsLocked() );
352 if( aSeg.Length() == 0 )
355 auto tSegment = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
356 tSegment->SetStart( aSeg.A );
357 tSegment->SetEnd( aSeg.B );
359 copyProps( *tSegment );
363 tArc->SetArcGeometry( dogbone_result->m_arc.GetP0(), dogbone_result->m_arc.GetArcMid(),
364 dogbone_result->m_arc.GetP1() );
369 addSegment(
SEG{ dogbone_result->m_arc.GetP0(), dogbone_result->m_updated_seg_a->
B } );
370 addSegment(
SEG{ dogbone_result->m_arc.GetP1(), dogbone_result->m_updated_seg_b->
B } );
383 return _(
"Extend Lines to Meet" );
391 return _(
"Unable to extend the selected lines to meet." );
395 return _(
"Some of the lines could not be extended to meet." );
426 const auto line_extender = [&](
const SEG& aSeg,
PCB_SHAPE& aLine )
429 if( !aSeg.
Contains( *intersection ) )
431 const int dist_start = ( *intersection - aSeg.
A ).EuclideanNorm();
432 const int dist_end = ( *intersection - aSeg.
B ).EuclideanNorm();
434 const VECTOR2I& furthest_pt = ( dist_start < dist_end ) ? aSeg.
B : aSeg.
A;
437 unsigned int edge_padding =
static_cast<unsigned>(
pcbIUScale.
mmToIU( 200 ) );
441 aLine.SetStart( furthest_pt );
442 aLine.SetEnd( new_end );
446 line_extender( seg_a, aLineA );
447 line_extender( seg_b, aLineB );
455 std::unique_ptr<SHAPE_POLY_SET> poly;
461 poly = std::make_unique<SHAPE_POLY_SET>( aPcbShape.
GetPolyShape() );
464 case SHAPE_T::RECTANGLE:
468 const std::vector<VECTOR2I> rect_pts = aPcbShape.
GetRectCorners();
472 for(
const VECTOR2I& pt : rect_pts )
477 poly = std::make_unique<SHAPE_POLY_SET>( std::move( rect_poly ) );
536 std::unique_ptr<PCB_SHAPE> new_poly_shape =
537 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::POLY );
540 new_poly_shape->SetPolyShape( poly_set );
544 new_poly_shape->SetLayer(
m_layer );
545 new_poly_shape->SetFilled(
m_filled );
547 handler.
AddNewItem( std::move( new_poly_shape ) );
554 return _(
"Merge polygons." );
562 return _(
"Unable to merge the selected polygons." );
566 return _(
"Some of the polygons could not be merged." );
581 return _(
"Subtract polygons." );
589 return _(
"Unable to subtract the selected polygons." );
593 return _(
"Some of the polygons could not be subtracted." );
615 working_polygons = std::move( working_copy );
622 return _(
"Intersect polygons." );
630 return _(
"Unable to intersect the selected polygons." );
634 return _(
"Some of the polygons could not be intersected." );
654 working_polygons = std::move( working_copy );
661 return _(
"Outset items." );
668 return _(
"Unable to outset the selected items." );
672 return _(
"Some of the items could not be outset." );
704 if( item_width.has_value() )
716 std::unique_ptr<PCB_SHAPE> new_shape =
717 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::POLY );
719 new_shape->SetPolyShape( new_poly );
720 new_shape->SetLayer( layer );
721 new_shape->SetWidth( width );
732 if( aChain.ArcCount() == 0 )
734 addPolygonalChain( aChain );
738 for(
size_t si = 0; si < aChain.GetSegmentCount(); ++si )
740 const SEG seg = aChain.GetSegment( si );
745 if( aChain.IsArcSegment( si ) )
748 std::unique_ptr<PCB_SHAPE> new_shape =
749 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
750 new_shape->SetStart( seg.
A );
751 new_shape->SetEnd( seg.
B );
752 new_shape->SetLayer( layer );
753 new_shape->SetWidth( width );
758 for(
size_t ai = 0; ai < aChain.ArcCount(); ++ai )
765 std::unique_ptr<PCB_SHAPE> new_shape =
766 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
768 new_shape->SetLayer( layer );
769 new_shape->SetWidth( width );
777 for(
int oi = 0; oi < aPoly.OutlineCount(); ++oi )
779 addChain( aPoly.Outline( oi ) );
783 const auto addRect = [&](
const SHAPE_RECT& aRect )
785 std::unique_ptr<PCB_SHAPE> new_shape =
786 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::RECTANGLE );
790 new_shape->SetPosition( aRect.GetPosition() );
791 new_shape->SetRectangleWidth( aRect.GetWidth() );
792 new_shape->SetRectangleHeight( aRect.GetHeight() );
799 new_shape->SetRectangleWidth( grid_rect.
GetWidth() );
800 new_shape->SetRectangleHeight( grid_rect.
GetHeight() );
803 new_shape->SetLayer( layer );
804 new_shape->SetWidth( width );
809 const auto addCircle = [&](
const CIRCLE& aCircle )
811 std::unique_ptr<PCB_SHAPE> new_shape =
812 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::CIRCLE );
813 new_shape->SetCenter( aCircle.Center );
814 new_shape->SetRadius( aCircle.Radius );
815 new_shape->SetLayer( layer );
816 new_shape->SetWidth( width );
821 const auto addCircleOrRect = [&](
const CIRCLE& aCircle )
825 addCircle( aCircle );
829 const VECTOR2I rVec{ aCircle.Radius, aCircle.Radius };
830 const SHAPE_RECT rect{ aCircle.Center - rVec, aCircle.Center + rVec };
835 switch( aItem.
Type() )
839 const PAD&
pad =
static_cast<const PAD&
>( aItem );
846 case PAD_SHAPE::RECTANGLE:
847 case PAD_SHAPE::ROUNDRECT:
848 case PAD_SHAPE::OVAL:
852 BOX2I box{
pad.GetPosition() - pad_size / 2, pad_size };
856 if( pad_shape == PAD_SHAPE::ROUNDRECT )
860 else if( pad_shape == PAD_SHAPE::OVAL )
862 radius += std::min( pad_size.
x, pad_size.
y ) / 2;
877 case PAD_SHAPE::CIRCLE:
880 const CIRCLE circle(
pad.GetPosition(), radius );
881 addCircleOrRect( circle );
885 case PAD_SHAPE::TRAPEZOID:
902 case SHAPE_T::RECTANGLE:
923 case SHAPE_T::CIRCLE:
927 addCircleOrRect( circle );
931 case SHAPE_T::SEGMENT:
947 chain.
Append( seg.
A - ext + perp );
948 chain.
Append( seg.
A - ext - perp );
949 chain.
Append( seg.
B + ext - perp );
950 chain.
Append( seg.
B + ext + perp );
974 arc.GetCentralAngle(), 0 };
976 arc.GetCentralAngle(), 0 };
983 if( inner.GetRadius() > 0 )
985 chain.
Append( inner.Reversed() );
constexpr EDA_IU_SCALE pcbIUScale
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual bool IsLocked() const
Represent basic circle geometry with utility geometry functions.
std::optional< wxString > GetStatusMessage() const override
Get a status message to show when the routine is complete.
wxString GetCommitDescription() const override
void ProcessLinePair(PCB_SHAPE &aLineA, PCB_SHAPE &aLineB) override
Perform the action on the pair of lines given.
bool IsHorizontal() const
KICAD_T Type() const
Returns the type of object.
EDA_ANGLE GetArcAngle() const
int GetRectangleWidth() const
SHAPE_POLY_SET & GetPolyShape()
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
void SetStart(const VECTOR2I &aStart)
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
std::vector< VECTOR2I > GetRectCorners() const
void SetEnd(const VECTOR2I &aEnd)
int GetRectangleHeight() const
virtual void MarkItemModified(BOARD_ITEM &aItem)=0
Report that the tool has modified an item on the board.
virtual void DeleteItem(BOARD_ITEM &aItem)=0
Report that the tool has deleted an item on the board.
virtual void AddNewItem(std::unique_ptr< BOARD_ITEM > aItem)=0
Report that the tools wants to add a new item to the board.
unsigned GetFailures() const
void AddFailure()
Mark that one of the actions failed.
unsigned GetSuccesses() const
void AddSuccess()
Mark that one of the actions succeeded.
bool ModifyLineOrDeleteIfZeroLength(PCB_SHAPE &aItem, const std::optional< SEG > &aSeg)
Helper function useful for multiple tools: modify a line or delete it if it has zero length.
BOARD_ITEM * GetBoard() const
The BOARD used when creating new shapes.
CHANGE_HANDLER & GetHandler()
Access the handler for making changes to the board.
wxString GetCommitDescription() const override
void ProcessLinePair(PCB_SHAPE &aLineA, PCB_SHAPE &aLineB) override
Perform the action on the pair of lines given.
const CHAMFER_PARAMS m_chamferParams
std::optional< wxString > GetStatusMessage() const override
Get a status message to show when the routine is complete.
wxString GetCommitDescription() const override
std::optional< wxString > GetStatusMessage() const override
Get a status message to show when the routine is complete.
void ProcessLinePair(PCB_SHAPE &aLineA, PCB_SHAPE &aLineB) override
Perform the action on the pair of lines given.
wxString GetCommitDescription() const override
void ProcessLinePair(PCB_SHAPE &aLineA, PCB_SHAPE &aLineB) override
Perform the action on the pair of lines given.
std::optional< wxString > GetStatusMessage() const override
Get a status message to show when the routine is complete.
void ProcessItem(BOARD_ITEM &aItem)
std::optional< wxString > GetStatusMessage() const override
Get a status message to show when the routine is complete.
const PARAMETERS m_params
wxString GetCommitDescription() const override
Class that represents an oval shape (rectangle with semicircular end caps)
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
int GetWidth() const override
VECTOR2I GetPosition() const override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
SHAPE_POLY_SET m_workingPolygons
This can be disjoint, which will be fixed at the end.
void Finalize()
Clear up any outstanding work.
SHAPE_POLY_SET & GetWorkingPolygons()
void ProcessShape(PCB_SHAPE &aPcbShape)
virtual bool ProcessSubsequentPolygon(const SHAPE_POLY_SET &aPolygon)=0
std::optional< wxString > GetStatusMessage() const override
Get a status message to show when the routine is complete.
wxString GetCommitDescription() const override
bool ProcessSubsequentPolygon(const SHAPE_POLY_SET &aPolygon) override
bool ProcessSubsequentPolygon(const SHAPE_POLY_SET &aPolygon) override
wxString GetCommitDescription() const override
std::optional< wxString > GetStatusMessage() const override
Get a status message to show when the routine is complete.
wxString GetCommitDescription() const override
std::optional< wxString > GetStatusMessage() const override
Get a status message to show when the routine is complete.
bool ProcessSubsequentPolygon(const SHAPE_POLY_SET &aPolygon) override
A round rectangle shape, based on a rectangle and a radius.
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aError, ERROR_LOC aErrorLoc) const
Get the polygonal representation of the roundrect.
bool Intersects(const SEG &aSeg) const
int Length() const
Return the length (this).
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
bool Contains(const SEG &aSeg) const
EDA_ANGLE Angle(const SEG &aOther) const
Determine the smallest angle between two segments.
const VECTOR2I & GetArcMid() const
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void SetWidth(int aWidth)
Set the width of all segments in the chain.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
int VertexCount(int aOutline=-1, int aHole=-1) const
Return the number of vertices in a given outline/hole.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const VECTOR2I & GetPosition() const
const VECTOR2I GetSize() const
static const int MIN_PRECISION_IU
This is the minimum precision for all the points in a shape.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
std::optional< CHAMFER_RESULT > ComputeChamferPoints(const SEG &aSegA, const SEG &aSegB, const CHAMFER_PARAMS &aChamferParams)
Compute the chamfer points for a given line pair and chamfer parameters.
std::optional< DOGBONE_RESULT > ComputeDogbone(const SEG &aSegA, const SEG &aSegB, int aDogboneRadius, bool aAddSlots)
Compute the dogbone geometry for a given line pair and dogbone parameters.
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_180
a few functions useful in geometry calculations.
VECTOR2< ret_type > GetClampedCoords(const VECTOR2< in_type > &aCoords, pad_type aPadding=1u)
Clamps a vector to values that can be negated, respecting numeric limits of coordinates data type wit...
static SHAPE_RECT GetRectRoundedToGridOutwards(const SHAPE_RECT &aRect, int aGridSize)
PCB_LAYER_ID
A quick note on layer IDs:
VECTOR2I RoundNW(const VECTOR2I &aVec, int aGridSize)
Round a vector to the nearest grid point in the NW direction.
VECTOR2I RoundSE(const VECTOR2I &aVec, int aGridSize)
Round a vector to the nearest grid point in the SE direction.
SHAPE_LINE_CHAIN ConvertToChain(const OVAL &aOval)
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
std::optional< VECTOR2I > OPT_VECTOR2I
constexpr int mmToIU(double mm) const
std::optional< int > gridRounding
VECTOR2I GetRotated(const VECTOR2I &aVector, const EDA_ANGLE &aAngle)
Return a new VECTOR2I that is the result of rotating aVector by aAngle.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I
Supplemental functions for working with vectors and simple objects that interact with vectors.