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." );
582 return _(
"Subtract polygons." );
590 return _(
"Unable to subtract the selected polygons." );
594 return _(
"Some of the polygons could not be subtracted." );
618 working_polygons = std::move( working_copy );
625 return _(
"Intersect polygons." );
633 return _(
"Unable to intersect the selected polygons." );
637 return _(
"Some of the polygons could not be intersected." );
659 working_polygons = std::move( working_copy );
666 return _(
"Outset items." );
673 return _(
"Unable to outset the selected items." );
677 return _(
"Some of the items could not be outset." );
709 if( item_width.has_value() )
721 std::unique_ptr<PCB_SHAPE> new_shape =
722 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::POLY );
724 new_shape->SetPolyShape( new_poly );
725 new_shape->SetLayer( layer );
726 new_shape->SetWidth( width );
737 if( aChain.ArcCount() == 0 )
739 addPolygonalChain( aChain );
743 for(
size_t si = 0; si < aChain.GetSegmentCount(); ++si )
745 const SEG seg = aChain.GetSegment( si );
750 if( aChain.IsArcSegment( si ) )
753 std::unique_ptr<PCB_SHAPE> new_shape =
754 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::SEGMENT );
755 new_shape->SetStart( seg.
A );
756 new_shape->SetEnd( seg.
B );
757 new_shape->SetLayer( layer );
758 new_shape->SetWidth( width );
763 for(
size_t ai = 0; ai < aChain.ArcCount(); ++ai )
770 std::unique_ptr<PCB_SHAPE> new_shape =
771 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::ARC );
773 new_shape->SetLayer( layer );
774 new_shape->SetWidth( width );
782 for(
int oi = 0; oi < aPoly.OutlineCount(); ++oi )
784 addChain( aPoly.Outline( oi ) );
788 const auto addRect = [&](
const SHAPE_RECT& aRect )
790 std::unique_ptr<PCB_SHAPE> new_shape =
791 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::RECTANGLE );
795 new_shape->SetPosition( aRect.GetPosition() );
796 new_shape->SetRectangleWidth( aRect.GetWidth() );
797 new_shape->SetRectangleHeight( aRect.GetHeight() );
804 new_shape->SetRectangleWidth( grid_rect.
GetWidth() );
805 new_shape->SetRectangleHeight( grid_rect.
GetHeight() );
808 new_shape->SetLayer( layer );
809 new_shape->SetWidth( width );
814 const auto addCircle = [&](
const CIRCLE& aCircle )
816 std::unique_ptr<PCB_SHAPE> new_shape =
817 std::make_unique<PCB_SHAPE>(
GetBoard(), SHAPE_T::CIRCLE );
818 new_shape->SetCenter( aCircle.Center );
819 new_shape->SetRadius( aCircle.Radius );
820 new_shape->SetLayer( layer );
821 new_shape->SetWidth( width );
826 const auto addCircleOrRect = [&](
const CIRCLE& aCircle )
830 addCircle( aCircle );
834 const VECTOR2I rVec{ aCircle.Radius, aCircle.Radius };
835 const SHAPE_RECT rect{ aCircle.Center - rVec, aCircle.Center + rVec };
840 switch( aItem.
Type() )
844 const PAD&
pad =
static_cast<const PAD&
>( aItem );
851 case PAD_SHAPE::RECTANGLE:
852 case PAD_SHAPE::ROUNDRECT:
853 case PAD_SHAPE::OVAL:
857 BOX2I box{
pad.GetPosition() - pad_size / 2, pad_size };
861 if( pad_shape == PAD_SHAPE::ROUNDRECT )
865 else if( pad_shape == PAD_SHAPE::OVAL )
867 radius += std::min( pad_size.
x, pad_size.
y ) / 2;
882 case PAD_SHAPE::CIRCLE:
885 const CIRCLE circle(
pad.GetPosition(), radius );
886 addCircleOrRect( circle );
890 case PAD_SHAPE::TRAPEZOID:
907 case SHAPE_T::RECTANGLE:
928 case SHAPE_T::CIRCLE:
932 addCircleOrRect( circle );
936 case SHAPE_T::SEGMENT:
952 chain.
Append( seg.
A - ext + perp );
953 chain.
Append( seg.
A - ext - perp );
954 chain.
Append( seg.
B + ext - perp );
955 chain.
Append( seg.
B + ext + perp );
979 arc.GetCentralAngle(), 0 };
981 arc.GetCentralAngle(), 0 };
988 if( inner.GetRadius() > 0 )
990 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 BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
POLYGON_MODE
Operations on polygons use a aFastMode param if aFastMode is PM_FAST (true) the result can be a weak ...
int VertexCount(int aOutline=-1, int aHole=-1) const
Return the number of vertices in a given outline/hole.
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
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.
int OutlineCount() const
Return the number of outlines in the set.
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.