45bool SegmentsShareEndpoint(
const SEG& aSegA,
const SEG& aSegB )
47 return ( aSegA.
A == aSegB.
A || aSegA.
A == aSegB.
B || aSegA.
B == aSegB.
A || aSegA.
B == aSegB.
B );
51std::pair<VECTOR2I*, VECTOR2I*> GetSharedEndpoints(
SEG& aSegA,
SEG& aSegB )
53 std::pair<VECTOR2I*, VECTOR2I*> result = {
nullptr,
nullptr };
55 if( aSegA.
A == aSegB.
A )
57 result = { &aSegA.
A, &aSegB.
A };
59 else if( aSegA.
A == aSegB.
B )
61 result = { &aSegA.
A, &aSegB.
B };
63 else if( aSegA.
B == aSegB.
A )
65 result = { &aSegA.
B, &aSegB.
A };
67 else if( aSegA.
B == aSegB.
B )
69 result = { &aSegA.
B, &aSegB.
B };
79 const std::optional<SEG>& aSeg )
81 wxASSERT_MSG( aLine.
GetShape() == SHAPE_T::SEGMENT,
"Can only modify segments" );
83 const bool removed = !aSeg.has_value() || aSeg->Length() == 0;
104 return _(
"Fillet Lines" );
112 return _(
"Unable to fillet the selected lines." );
116 return _(
"Some of the lines could not be filleted." );
130 auto [a_pt, b_pt] = GetSharedEndpoints( seg_a, seg_b );
147 VECTOR2I segToVec = aSegment.NearestPoint( aVecToTest ) - aVecToTest;
152 aPointToSet.
x = aVecToTest.x;
153 aPointToSet.
y = aVecToTest.y;
161 if( !setIfPointOnSeg( t1newPoint, seg_a, sArc.
GetP0() )
162 && !setIfPointOnSeg( t2newPoint, seg_b, sArc.
GetP0() ) )
168 if( !setIfPointOnSeg( t1newPoint, seg_a, sArc.
GetP1() )
169 && !setIfPointOnSeg( t2newPoint, seg_b, sArc.
GetP1() ) )
175 auto tArc = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
180 tArc->SetWidth( aLineA.
GetWidth() );
181 tArc->SetLayer( aLineA.
GetLayer() );
182 tArc->SetLocked( aLineA.
IsLocked() );
199 return _(
"Chamfer Lines" );
207 return _(
"Unable to chamfer the selected lines." );
211 return _(
"Some of the lines could not be chamfered." );
228 if( !SegmentsShareEndpoint( seg_a, seg_b ) )
234 std::optional<CHAMFER_RESULT> chamfer_result =
237 if( !chamfer_result )
243 auto tSegment = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
245 tSegment->SetStart( chamfer_result->m_chamfer.A );
246 tSegment->SetEnd( chamfer_result->m_chamfer.B );
249 tSegment->SetWidth( aLineA.
GetWidth() );
250 tSegment->SetLayer( aLineA.
GetLayer() );
251 tSegment->SetLocked( aLineA.
IsLocked() );
266 return _(
"Dogbone Corners" );
276 msg +=
_(
"Unable to add dogbone corners to the selected lines." );
280 msg +=
_(
"Some of the lines could not have dogbone corners added." );
288 msg +=
_(
"Some of the dogbone corners are too narrow to fit a "
289 "cutter of the specified radius." );
292 msg +=
_(
" Consider enabling the 'Add Slots' option." );
294 msg +=
_(
" Slots were added." );
312 auto [a_pt, b_pt] = GetSharedEndpoints( seg_a, seg_b );
326 std::optional<DOGBONE_RESULT> dogbone_result =
329 if( !dogbone_result )
335 if( dogbone_result->m_small_arc_mouth )
343 auto tArc = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
345 const auto copyProps = [&](
PCB_SHAPE& aShape )
347 aShape.SetWidth( aLineA.
GetWidth() );
348 aShape.SetLayer( aLineA.
GetLayer() );
349 aShape.SetLocked( aLineA.
IsLocked() );
354 if( aSeg.Length() == 0 )
357 auto tSegment = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
358 tSegment->SetStart( aSeg.A );
359 tSegment->SetEnd( aSeg.B );
361 copyProps( *tSegment );
365 tArc->SetArcGeometry( dogbone_result->m_arc.GetP0(), dogbone_result->m_arc.GetArcMid(),
366 dogbone_result->m_arc.GetP1() );
371 addSegment(
SEG{ dogbone_result->m_arc.GetP0(), dogbone_result->m_updated_seg_a->
B } );
372 addSegment(
SEG{ dogbone_result->m_arc.GetP1(), dogbone_result->m_updated_seg_b->
B } );
385 return _(
"Extend Lines to Meet" );
393 return _(
"Unable to extend the selected lines to meet." );
397 return _(
"Some of the lines could not be extended to meet." );
428 const auto line_extender = [&](
const SEG& aSeg,
PCB_SHAPE& aLine )
431 if( !aSeg.
Contains( *intersection ) )
433 const int dist_start = ( *intersection - aSeg.
A ).EuclideanNorm();
434 const int dist_end = ( *intersection - aSeg.
B ).EuclideanNorm();
436 const VECTOR2I& furthest_pt = ( dist_start < dist_end ) ? aSeg.
B : aSeg.
A;
439 unsigned int edge_padding =
static_cast<unsigned>(
pcbIUScale.
mmToIU( 200 ) );
443 aLine.SetStart( furthest_pt );
444 aLine.SetEnd( new_end );
448 line_extender( seg_a, aLineA );
449 line_extender( seg_b, aLineB );
457 std::unique_ptr<SHAPE_POLY_SET> poly;
463 poly = std::make_unique<SHAPE_POLY_SET>( aPcbShape.
GetPolyShape() );
466 case SHAPE_T::RECTANGLE:
470 const std::vector<VECTOR2I> rect_pts = aPcbShape.
GetRectCorners();
474 for(
const VECTOR2I& pt : rect_pts )
479 poly = std::make_unique<SHAPE_POLY_SET>( std::move( rect_poly ) );
538 std::unique_ptr<PCB_SHAPE> new_poly_shape =
539 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::POLY );
542 new_poly_shape->SetPolyShape( poly_set );
546 new_poly_shape->SetLayer(
m_layer );
547 new_poly_shape->SetFilled(
m_filled );
549 handler.
AddNewItem( std::move( new_poly_shape ) );
556 return _(
"Merge polygons." );
564 return _(
"Unable to merge the selected polygons." );
568 return _(
"Some of the polygons could not be merged." );
583 return _(
"Subtract polygons." );
591 return _(
"Unable to subtract the selected polygons." );
595 return _(
"Some of the polygons could not be subtracted." );
617 working_polygons = std::move( working_copy );
624 return _(
"Intersect polygons." );
632 return _(
"Unable to intersect the selected polygons." );
636 return _(
"Some of the polygons could not be intersected." );
656 working_polygons = std::move( working_copy );
663 return _(
"Outset items." );
670 return _(
"Unable to outset the selected items." );
674 return _(
"Some of the items could not be outset." );
706 if( item_width.has_value() )
718 std::unique_ptr<PCB_SHAPE> new_shape =
719 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::POLY );
721 new_shape->SetPolyShape( new_poly );
722 new_shape->SetLayer( layer );
723 new_shape->SetWidth( width );
734 if( aChain.ArcCount() == 0 )
736 addPolygonalChain( aChain );
740 for(
size_t si = 0; si < aChain.GetSegmentCount(); ++si )
742 const SEG seg = aChain.GetSegment( si );
747 if( aChain.IsArcSegment( si ) )
750 std::unique_ptr<PCB_SHAPE> new_shape =
751 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
752 new_shape->SetStart( seg.
A );
753 new_shape->SetEnd( seg.
B );
754 new_shape->SetLayer( layer );
755 new_shape->SetWidth( width );
760 for(
size_t ai = 0; ai < aChain.ArcCount(); ++ai )
767 std::unique_ptr<PCB_SHAPE> new_shape =
768 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
770 new_shape->SetLayer( layer );
771 new_shape->SetWidth( width );
779 for(
int oi = 0; oi < aPoly.OutlineCount(); ++oi )
781 addChain( aPoly.Outline( oi ) );
785 const auto addRect = [&](
const SHAPE_RECT& aRect )
787 std::unique_ptr<PCB_SHAPE> new_shape =
788 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::RECTANGLE );
792 new_shape->SetPosition( aRect.GetPosition() );
793 new_shape->SetRectangleWidth( aRect.GetWidth() );
794 new_shape->SetRectangleHeight( aRect.GetHeight() );
801 new_shape->SetRectangleWidth( grid_rect.
GetWidth() );
802 new_shape->SetRectangleHeight( grid_rect.
GetHeight() );
805 new_shape->SetLayer( layer );
806 new_shape->SetWidth( width );
811 const auto addCircle = [&](
const CIRCLE& aCircle )
813 std::unique_ptr<PCB_SHAPE> new_shape =
814 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::CIRCLE );
815 new_shape->SetCenter( aCircle.Center );
816 new_shape->SetRadius( aCircle.Radius );
817 new_shape->SetLayer( layer );
818 new_shape->SetWidth( width );
823 const auto addCircleOrRect = [&](
const CIRCLE& aCircle )
827 addCircle( aCircle );
831 const VECTOR2I rVec{ aCircle.Radius, aCircle.Radius };
832 const SHAPE_RECT rect{ aCircle.Center - rVec, aCircle.Center + rVec };
837 switch( aItem.
Type() )
841 const PAD&
pad =
static_cast<const PAD&
>( aItem );
848 case PAD_SHAPE::RECTANGLE:
849 case PAD_SHAPE::ROUNDRECT:
850 case PAD_SHAPE::OVAL:
854 BOX2I box{
pad.GetPosition() - pad_size / 2, pad_size };
858 if( pad_shape == PAD_SHAPE::ROUNDRECT )
862 else if( pad_shape == PAD_SHAPE::OVAL )
864 radius += std::min( pad_size.
x, pad_size.
y ) / 2;
879 case PAD_SHAPE::CIRCLE:
883 addCircleOrRect( circle );
887 case PAD_SHAPE::TRAPEZOID:
904 case SHAPE_T::RECTANGLE:
933 case SHAPE_T::CIRCLE:
937 addCircleOrRect( circle );
941 case SHAPE_T::SEGMENT:
984 arc.GetCentralAngle(), 0 };
986 arc.GetCentralAngle(), 0 };
993 if( inner.GetRadius() > 0 )
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.
Hold a translatable error message and may be used when throwing exceptions containing a translated er...
const wxString What() const
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.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
This file is part of the common library.
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
const SHAPE_LINE_CHAIN chain
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.