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" );
111 return _(
"Unable to fillet the selected lines." );
113 return _(
"Some of the lines could not be filleted." );
127 auto [a_pt, b_pt] = GetSharedEndpoints( seg_a, seg_b );
141 auto setIfPointOnSeg =
144 VECTOR2I segToVec = aSegment.NearestPoint( aVecToTest ) - aVecToTest;
149 aPointToSet.
x = aVecToTest.x;
150 aPointToSet.
y = aVecToTest.y;
158 if( !setIfPointOnSeg( t1newPoint, seg_a, sArc.
GetP0() )
159 && !setIfPointOnSeg( t2newPoint, seg_b, sArc.
GetP0() ) )
165 if( !setIfPointOnSeg( t1newPoint, seg_a, sArc.
GetP1() )
166 && !setIfPointOnSeg( t2newPoint, seg_b, sArc.
GetP1() ) )
172 auto tArc = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
177 tArc->SetWidth( aLineA.
GetWidth() );
178 tArc->SetLayer( aLineA.
GetLayer() );
179 tArc->SetLocked( aLineA.
IsLocked() );
196 return _(
"Chamfer Lines" );
203 return _(
"Unable to chamfer the selected lines." );
205 return _(
"Some of the lines could not be chamfered." );
222 if( !SegmentsShareEndpoint( seg_a, seg_b ) )
228 std::optional<CHAMFER_RESULT> chamfer_result =
231 if( !chamfer_result )
237 auto tSegment = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
239 tSegment->SetStart( chamfer_result->m_chamfer.A );
240 tSegment->SetEnd( chamfer_result->m_chamfer.B );
243 tSegment->SetWidth( aLineA.
GetWidth() );
244 tSegment->SetLayer( aLineA.
GetLayer() );
245 tSegment->SetLocked( aLineA.
IsLocked() );
260 return _(
"Dogbone Corners" );
269 msg +=
_(
"Unable to add dogbone corners to the selected lines." );
271 msg +=
_(
"Some of the lines could not have dogbone corners added." );
278 msg +=
_(
"Some of the dogbone corners are too narrow to fit a "
279 "cutter of the specified radius." );
282 msg +=
_(
" Consider enabling the 'Add Slots' option." );
284 msg +=
_(
" Slots were added." );
302 auto [a_pt, b_pt] = GetSharedEndpoints( seg_a, seg_b );
316 std::optional<DOGBONE_RESULT> dogbone_result =
319 if( !dogbone_result )
325 if( dogbone_result->m_small_arc_mouth )
333 auto tArc = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
335 const auto copyProps = [&](
PCB_SHAPE& aShape )
337 aShape.SetWidth( aLineA.
GetWidth() );
338 aShape.SetLayer( aLineA.
GetLayer() );
339 aShape.SetLocked( aLineA.
IsLocked() );
344 if( aSeg.Length() == 0 )
347 auto tSegment = std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
348 tSegment->SetStart( aSeg.A );
349 tSegment->SetEnd( aSeg.B );
351 copyProps( *tSegment );
355 tArc->SetArcGeometry( dogbone_result->m_arc.GetP0(), dogbone_result->m_arc.GetArcMid(),
356 dogbone_result->m_arc.GetP1() );
361 addSegment(
SEG{ dogbone_result->m_arc.GetP0(), dogbone_result->m_updated_seg_a->
B } );
362 addSegment(
SEG{ dogbone_result->m_arc.GetP1(), dogbone_result->m_updated_seg_b->
B } );
375 return _(
"Extend Lines to Meet" );
382 return _(
"Unable to extend the selected lines to meet." );
384 return _(
"Some of the lines could not be extended to meet." );
415 const auto line_extender = [&](
const SEG& aSeg,
PCB_SHAPE& aLine )
418 if( !aSeg.
Contains( *intersection ) )
420 const int dist_start = ( *intersection - aSeg.
A ).EuclideanNorm();
421 const int dist_end = ( *intersection - aSeg.
B ).EuclideanNorm();
423 const VECTOR2I& furthest_pt = ( dist_start < dist_end ) ? aSeg.
B : aSeg.
A;
426 unsigned int edge_padding =
static_cast<unsigned>(
pcbIUScale.
mmToIU( 200 ) );
430 aLine.SetStart( furthest_pt );
431 aLine.SetEnd( new_end );
435 line_extender( seg_a, aLineA );
436 line_extender( seg_b, aLineB );
444 std::unique_ptr<SHAPE_POLY_SET> poly;
450 poly = std::make_unique<SHAPE_POLY_SET>( aPcbShape.
GetPolyShape() );
455 case SHAPE_T::RECTANGLE:
457 poly = std::make_unique<SHAPE_POLY_SET>();
459 const std::vector<VECTOR2I> rect_pts = aPcbShape.
GetRectCorners();
463 for(
const VECTOR2I& pt : rect_pts )
469 case SHAPE_T::CIRCLE:
471 poly = std::make_unique<SHAPE_POLY_SET>();
538 std::unique_ptr<PCB_SHAPE> new_poly_shape =
539 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::POLY );
543 new_poly_shape->SetPolyShape( poly_set );
546 new_poly_shape->SetWidth(
m_width );
547 new_poly_shape->SetLayer(
m_layer );
550 handler.
AddNewItem( std::move( new_poly_shape ) );
557 return _(
"Merge Polygons" );
564 return _(
"Unable to merge the selected polygons." );
566 return _(
"Some of the polygons could not be merged." );
584 return _(
"Subtract Polygons" );
591 return _(
"Unable to subtract the selected polygons." );
593 return _(
"Some of the polygons could not be subtracted." );
609 working_polygons = std::move( working_copy );
616 return _(
"Intersect Polygons" );
623 return _(
"Unable to intersect the selected polygons." );
625 return _(
"Some of the polygons could not be intersected." );
649 working_polygons = std::move( working_copy );
656 return _(
"Outset Items" );
662 return _(
"Unable to outset the selected items." );
664 return _(
"Some of the items could not be outset." );
697 if( item_width.has_value() )
707 std::unique_ptr<PCB_SHAPE> new_shape =
708 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::POLY );
710 new_shape->SetPolyShape( new_poly );
711 new_shape->SetLayer( layer );
712 new_shape->SetWidth( width );
723 if( aChain.ArcCount() == 0 )
725 addPolygonalChain( aChain );
729 for(
size_t si = 0; si < aChain.GetSegmentCount(); ++si )
731 const SEG seg = aChain.GetSegment( si );
736 if( aChain.IsArcSegment( si ) )
739 std::unique_ptr<PCB_SHAPE> new_shape =
740 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
741 new_shape->SetStart( seg.
A );
742 new_shape->SetEnd( seg.
B );
743 new_shape->SetLayer( layer );
744 new_shape->SetWidth( width );
749 for(
size_t ai = 0; ai < aChain.ArcCount(); ++ai )
756 std::unique_ptr<PCB_SHAPE> new_shape =
757 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
759 new_shape->SetLayer( layer );
760 new_shape->SetWidth( width );
768 for(
int oi = 0; oi < aPoly.OutlineCount(); ++oi )
770 addChain( aPoly.Outline( oi ) );
774 const auto addRect = [&](
const SHAPE_RECT& aRect )
776 std::unique_ptr<PCB_SHAPE> new_shape =
777 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::RECTANGLE );
781 new_shape->SetPosition( aRect.GetPosition() );
782 new_shape->SetRectangleWidth( aRect.GetWidth() );
783 new_shape->SetRectangleHeight( aRect.GetHeight() );
790 new_shape->SetRectangleWidth( grid_rect.
GetWidth() );
791 new_shape->SetRectangleHeight( grid_rect.
GetHeight() );
794 new_shape->SetLayer( layer );
795 new_shape->SetWidth( width );
800 const auto addCircle = [&](
const CIRCLE& aCircle )
802 std::unique_ptr<PCB_SHAPE> new_shape =
803 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::CIRCLE );
804 new_shape->SetCenter( aCircle.Center );
805 new_shape->SetRadius( aCircle.Radius );
806 new_shape->SetLayer( layer );
807 new_shape->SetWidth( width );
812 const auto addCircleOrRect = [&](
const CIRCLE& aCircle )
816 addCircle( aCircle );
820 const VECTOR2I rVec{ aCircle.Radius, aCircle.Radius };
821 const SHAPE_RECT rect{ aCircle.Center - rVec, aCircle.Center + rVec };
826 switch( aItem.
Type() )
830 const PAD&
pad =
static_cast<const PAD&
>( aItem );
837 case PAD_SHAPE::RECTANGLE:
838 case PAD_SHAPE::ROUNDRECT:
839 case PAD_SHAPE::OVAL:
843 BOX2I box{
pad.GetPosition() - pad_size / 2, pad_size };
847 if( pad_shape == PAD_SHAPE::ROUNDRECT )
851 else if( pad_shape == PAD_SHAPE::OVAL )
853 radius += std::min( pad_size.
x, pad_size.
y ) / 2;
868 case PAD_SHAPE::CIRCLE:
872 addCircleOrRect(
circle );
876 case PAD_SHAPE::TRAPEZOID:
893 case SHAPE_T::RECTANGLE:
922 case SHAPE_T::CIRCLE:
926 addCircleOrRect(
circle );
930 case SHAPE_T::SEGMENT:
973 arc.GetCentralAngle(), 0 };
975 arc.GetCentralAngle(), 0 };
982 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.
bool IsLocked() const override
Represent basic circle geometry with utility geometry functions.
std::optional< wxString > GetStatusMessage(int aSegmentCount) 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
FILL_T GetFillMode() 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
std::optional< wxString > GetStatusMessage(int aSegmentCount) 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.
const CHAMFER_PARAMS m_chamferParams
wxString GetCommitDescription() const override
std::optional< wxString > GetStatusMessage(int aSegmentCount) 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.
std::optional< wxString > GetStatusMessage(int aSegmentCount) 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.
void ProcessItem(BOARD_ITEM &aItem)
const PARAMETERS m_params
wxString GetCommitDescription() const override
std::optional< wxString > GetStatusMessage() const
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) 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.
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.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
SHAPE_POLY_SET UnitSet(int aPolygonIndex)
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 FULL_CIRCLE
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
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
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.